From 65e19fa8a8404ac7b3ef9bf7e952cc3b20342bc7 Mon Sep 17 00:00:00 2001 From: wangchunsheng Date: Tue, 21 Feb 2012 07:22:58 +0000 Subject: [PATCH] * convert to unix format. --- bin/initext.php | 120 +- .../home/admin/www/includes/lang/Chinese.php | 822 +- build/windows/xampp/build.php | 578 +- build/windows/xampp/index.php | 44 +- config/config.php | 242 +- lib/api/api.class.php | 3010 ++-- lib/pclzip/pclzip.class.php | 11388 ++++++++-------- lib/phpmailer/class.smtp.php | 1626 +-- lib/phpmailer/language/phpmailer.lang-br.php | 50 +- lib/phpmailer/language/phpmailer.lang-ca.php | 50 +- lib/phpmailer/language/phpmailer.lang-cz.php | 48 +- lib/phpmailer/language/phpmailer.lang-de.php | 48 +- lib/phpmailer/language/phpmailer.lang-dk.php | 50 +- lib/phpmailer/language/phpmailer.lang-es.php | 50 +- lib/phpmailer/language/phpmailer.lang-fi.php | 52 +- lib/phpmailer/language/phpmailer.lang-fo.php | 52 +- lib/phpmailer/language/phpmailer.lang-fr.php | 48 +- lib/phpmailer/language/phpmailer.lang-hu.php | 48 +- lib/phpmailer/language/phpmailer.lang-it.php | 52 +- lib/phpmailer/language/phpmailer.lang-ja.php | 50 +- lib/phpmailer/language/phpmailer.lang-nl.php | 48 +- lib/phpmailer/language/phpmailer.lang-no.php | 48 +- lib/phpmailer/language/phpmailer.lang-pl.php | 48 +- lib/phpmailer/language/phpmailer.lang-ro.php | 52 +- lib/phpmailer/language/phpmailer.lang-ru.php | 48 +- lib/phpmailer/language/phpmailer.lang-se.php | 50 +- lib/phpmailer/language/phpmailer.lang-tr.php | 52 +- module/action/control.php | 132 +- module/action/lang/zh-cn.php | 362 +- module/action/lang/zh-tw.php | 362 +- module/action/model.php | 1104 +- module/action/view/trash.html.php | 98 +- module/admin/control.php | 182 +- module/admin/lang/en.php | 114 +- module/admin/lang/zh-cn.php | 114 +- module/admin/lang/zh-tw.php | 114 +- module/admin/model.php | 414 +- module/admin/view/browsecompany.html.php | 94 +- module/api/control.php | 100 +- module/api/lang/en.php | 26 +- module/api/lang/zh-cn.php | 26 +- module/api/lang/zh-tw.php | 26 +- module/api/model.php | 30 +- module/bug/control.php | 1894 +-- module/bug/lang/en.php | 624 +- module/bug/lang/zh-cn.php | 624 +- module/bug/lang/zh-tw.php | 624 +- module/bug/model.php | 1976 +-- module/bug/view/activate.html.php | 86 +- module/bug/view/browse.custom.html.php | 142 +- module/bug/view/browse.html.php | 350 +- module/bug/view/close.html.php | 62 +- module/bug/view/confirmbug.html.php | 62 +- module/bug/view/create.html.php | 204 +- module/bug/view/customfields.html.php | 98 +- module/bug/view/edit.html.php | 412 +- module/bug/view/export.html.php | 26 +- module/bug/view/report.html.php | 124 +- module/bug/view/resolve.html.php | 94 +- module/bug/view/sendmail.html.php | 44 +- module/bug/view/view.html.php | 544 +- module/build/control.php | 372 +- module/build/lang/en.php | 70 +- module/build/lang/zh-cn.php | 70 +- module/build/lang/zh-tw.php | 70 +- module/build/model.php | 304 +- module/build/view/create.html.php | 194 +- module/build/view/edit.html.php | 194 +- module/build/view/view.html.php | 234 +- module/common/control.php | 530 +- module/common/lang/en.php | 600 +- module/common/lang/zh-cn.php | 600 +- module/common/lang/zh-tw.php | 600 +- module/common/model.php | 732 +- module/common/view/footer.html.php | 54 +- module/common/view/footer.lite.html.php | 18 +- module/company/control.php | 472 +- module/company/lang/en.php | 78 +- module/company/lang/zh-cn.php | 78 +- module/company/lang/zh-tw.php | 78 +- module/company/model.php | 246 +- module/company/view/browse.html.php | 156 +- module/company/view/create.html.php | 112 +- module/company/view/dynamic.html.php | 124 +- module/company/view/edit.html.php | 112 +- module/convert/control.php | 480 +- module/convert/converter/bugfree.php | 176 +- module/convert/converter/bugfree1.php | 636 +- module/convert/converter/bugfree2.php | 1060 +- module/convert/converter/redmine.php | 176 +- module/convert/converter/redmine1.1.php | 1644 +-- module/convert/lang/en.php | 218 +- module/convert/lang/zh-cn.php | 218 +- module/convert/lang/zh-tw.php | 218 +- module/convert/model.php | 188 +- module/convert/view/checkconfig.html.php | 58 +- module/convert/view/execute.html.php | 36 +- module/convert/view/index.html.php | 36 +- module/convert/view/selectsource.html.php | 62 +- module/convert/view/setconfig.html.php | 46 +- module/dept/control.php | 202 +- module/dept/lang/en.php | 46 +- module/dept/lang/zh-cn.php | 46 +- module/dept/lang/zh-tw.php | 46 +- module/dept/model.php | 604 +- module/dept/view/browse.html.php | 134 +- module/doc/control.php | 840 +- module/doc/lang/en.php | 130 +- module/doc/lang/zh-cn.php | 130 +- module/doc/lang/zh-tw.php | 130 +- module/doc/model.php | 562 +- module/doc/view/browse.html.php | 164 +- module/doc/view/create.html.php | 140 +- module/doc/view/createlib.html.php | 52 +- module/doc/view/edit.html.php | 136 +- module/doc/view/editlib.html.php | 56 +- module/doc/view/view.html.php | 150 +- module/editor/control.php | 328 +- module/editor/model.php | 1122 +- module/editor/view/edit.html.php | 140 +- module/editor/view/extend.html.php | 58 +- module/editor/view/index.html.php | 48 +- module/editor/view/newpage.html.php | 66 +- module/extension/control.php | 760 +- module/extension/lang/en.php | 190 +- module/extension/lang/zh-cn.php | 190 +- module/extension/lang/zh-tw.php | 190 +- module/extension/model.php | 1508 +- module/extension/view/activate.html.php | 66 +- module/extension/view/browse.html.php | 122 +- module/extension/view/checkscore.html.php | 56 +- module/extension/view/deactivate.html.php | 62 +- module/extension/view/erase.html.php | 62 +- module/extension/view/install.html.php | 98 +- module/extension/view/obtain.html.php | 226 +- module/extension/view/structure.html.php | 52 +- module/extension/view/uninstall.html.php | 62 +- module/extension/view/upload.html.php | 38 +- module/extension/view/waring.htm.php | 58 +- module/file/control.php | 532 +- module/file/lang/en.php | 46 +- module/file/lang/zh-cn.php | 46 +- module/file/lang/zh-tw.php | 46 +- module/file/model.php | 420 +- module/file/view/edit.html.php | 82 +- module/file/view/export.html.php | 102 +- module/file/view/export2csv.html.php | 48 +- module/file/view/export2html.html.php | 88 +- module/file/view/export2xml.html.php | 72 +- module/group/control.php | 448 +- module/group/lang/en.php | 114 +- module/group/lang/resource.php | 716 +- module/group/lang/zh-cn.php | 114 +- module/group/lang/zh-tw.php | 114 +- module/group/model.php | 502 +- module/group/view/browse.html.php | 100 +- module/group/view/copy.html.php | 64 +- module/group/view/create.html.php | 56 +- module/group/view/edit.html.php | 56 +- module/group/view/managemember.html.php | 94 +- module/group/view/managepriv.html.php | 34 +- module/group/view/privbygroup.html.php | 112 +- module/group/view/privbymodule.html.php | 90 +- module/help/control.php | 92 +- module/help/model.php | 30 +- module/help/view/field.html.php | 38 +- module/index/control.php | 96 +- module/index/model.php | 30 +- module/install/control.php | 402 +- module/install/lang/en.php | 226 +- module/install/lang/zh-cn.php | 226 +- module/install/lang/zh-tw.php | 226 +- module/install/model.php | 746 +- module/install/view/index.html.php | 66 +- module/install/view/step1.html.php | 192 +- module/install/view/step2.html.php | 124 +- module/install/view/step3.html.php | 144 +- module/install/view/step4.html.php | 104 +- module/mail/control.php | 226 +- module/mail/model.php | 536 +- module/mail/view/save.html.php | 50 +- module/mail/view/set.html.php | 220 +- module/misc/control.php | 116 +- module/misc/lang/en.php | 116 +- module/misc/lang/zh-cn.php | 116 +- module/misc/lang/zh-tw.php | 116 +- module/misc/model.php | 32 +- module/my/control.php | 758 +- module/my/model.php | 52 +- module/my/view/bug.html.php | 130 +- module/my/view/dynamic.html.php | 110 +- module/my/view/editprofile.html.php | 200 +- module/my/view/index.html.php | 62 +- module/my/view/profile.html.php | 240 +- module/my/view/project.html.php | 92 +- module/my/view/story.html.php | 130 +- module/my/view/task.html.php | 164 +- module/my/view/team.html.php | 28 +- module/my/view/testcase.html.php | 118 +- module/my/view/testtask.html.php | 120 +- module/my/view/todo.html.php | 178 +- module/product/control.php | 798 +- module/product/lang/en.php | 168 +- module/product/lang/zh-cn.php | 168 +- module/product/lang/zh-tw.php | 168 +- module/product/model.php | 970 +- module/product/view/browse.html.php | 240 +- module/product/view/create.html.php | 106 +- module/product/view/doc.html.php | 108 +- module/product/view/dynamic.html.php | 112 +- module/product/view/edit.html.php | 114 +- module/product/view/index.html.php | 108 +- module/product/view/project.html.php | 88 +- module/product/view/roadmap.html.php | 98 +- module/product/view/view.html.php | 302 +- module/productplan/control.php | 384 +- module/productplan/lang/en.php | 68 +- module/productplan/lang/zh-cn.php | 64 +- module/productplan/lang/zh-tw.php | 64 +- module/productplan/model.php | 250 +- module/productplan/view/browse.html.php | 98 +- module/productplan/view/create.html.php | 100 +- module/productplan/view/edit.html.php | 100 +- module/productplan/view/linkstory.html.php | 178 +- module/productplan/view/view.html.php | 168 +- module/project/control.php | 2508 ++-- module/project/lang/en.php | 336 +- module/project/lang/zh-cn.php | 336 +- module/project/lang/zh-tw.php | 336 +- module/project/model.php | 2130 +-- module/project/view/browse.html.php | 308 +- module/project/view/bug.html.php | 126 +- module/project/view/build.html.php | 108 +- module/project/view/burn.html.php | 42 +- module/project/view/computeburn.html.php | 36 +- module/project/view/create.html.php | 172 +- module/project/view/doc.html.php | 102 +- module/project/view/dynamic.html.php | 112 +- module/project/view/edit.html.php | 172 +- module/project/view/grouptask.html.php | 236 +- module/project/view/importbug.html.php | 124 +- module/project/view/importtask.html.php | 118 +- module/project/view/index.html.php | 96 +- module/project/view/linkstory.html.php | 106 +- module/project/view/managechilds.html.php | 58 +- module/project/view/managemembers.html.php | 120 +- module/project/view/manageproducts.html.php | 46 +- module/project/view/sendmail.html.php | 44 +- module/project/view/story.html.php | 148 +- module/project/view/task.html.php | 248 +- module/project/view/team.html.php | 112 +- module/project/view/testtask.html.php | 108 +- module/project/view/tips.html.php | 22 +- module/project/view/view.html.php | 192 +- module/qa/control.php | 48 +- module/qa/lang/en.php | 26 +- module/qa/lang/zh-cn.php | 26 +- module/qa/lang/zh-tw.php | 26 +- module/qa/model.php | 30 +- module/qa/view/index.html.php | 32 +- module/release/control.php | 388 +- module/release/lang/en.php | 64 +- module/release/lang/zh-cn.php | 64 +- module/release/lang/zh-tw.php | 64 +- module/release/model.php | 204 +- module/release/view/browse.html.php | 92 +- module/release/view/create.html.php | 80 +- module/release/view/edit.html.php | 174 +- module/release/view/view.html.php | 218 +- module/report/control.php | 28 +- module/report/lang/en.php | 62 +- module/report/lang/zh-cn.php | 62 +- module/report/lang/zh-tw.php | 62 +- module/report/model.php | 462 +- module/search/control.php | 232 +- module/search/lang/en.php | 92 +- module/search/lang/zh-cn.php | 92 +- module/search/lang/zh-tw.php | 92 +- module/search/model.php | 538 +- module/search/view/buildform.html.php | 524 +- module/search/view/select.html.php | 182 +- module/setting/model.php | 248 +- module/story/control.php | 1630 +-- module/story/lang/en.php | 444 +- module/story/lang/zh-cn.php | 444 +- module/story/lang/zh-tw.php | 444 +- module/story/model.php | 2422 ++-- module/story/view/activate.html.php | 72 +- module/story/view/batchcreate.html.php | 98 +- module/story/view/change.html.php | 104 +- module/story/view/close.html.php | 84 +- module/story/view/create.html.php | 146 +- module/story/view/edit.html.php | 278 +- module/story/view/export.html.php | 26 +- module/story/view/report.html.php | 124 +- module/story/view/review.html.php | 136 +- module/story/view/sendmail.html.php | 44 +- module/story/view/view.html.php | 546 +- module/task/control.php | 1460 +- module/task/lang/en.php | 358 +- module/task/lang/zh-cn.php | 358 +- module/task/lang/zh-tw.php | 358 +- module/task/model.php | 1800 +-- module/task/view/activate.html.php | 80 +- module/task/view/assignto.html.php | 62 +- module/task/view/batchcreate.html.php | 102 +- module/task/view/browse.html.php | 72 +- module/task/view/cancel.html.php | 54 +- module/task/view/close.html.php | 54 +- module/task/view/create.html.php | 172 +- module/task/view/edit.html.php | 290 +- module/task/view/export.html.php | 26 +- module/task/view/finish.html.php | 62 +- module/task/view/import.html.php | 116 +- module/task/view/report.html.php | 126 +- module/task/view/sendmail.html.php | 44 +- module/task/view/start.html.php | 70 +- module/task/view/view.html.php | 364 +- module/testcase/control.php | 1100 +- module/testcase/lang/en.php | 270 +- module/testcase/lang/zh-cn.php | 270 +- module/testcase/lang/zh-tw.php | 270 +- module/testcase/model.php | 602 +- module/testcase/view/batchcreate.html.php | 90 +- module/testcase/view/browse.html.php | 212 +- module/testcase/view/create.html.php | 194 +- module/testcase/view/edit.html.php | 264 +- module/testcase/view/export.html.php | 26 +- module/testcase/view/index.html.php | 30 +- module/testcase/view/view.html.php | 396 +- module/testtask/control.php | 942 +- module/testtask/lang/en.php | 132 +- module/testtask/lang/zh-cn.php | 132 +- module/testtask/lang/zh-tw.php | 132 +- module/testtask/model.php | 690 +- module/testtask/view/browse.html.php | 112 +- module/testtask/view/cases.html.php | 202 +- module/testtask/view/create.html.php | 134 +- module/testtask/view/edit.html.php | 112 +- module/testtask/view/linkcase.html.php | 136 +- module/testtask/view/results.html.php | 98 +- module/testtask/view/runcase.html.php | 118 +- module/testtask/view/view.html.php | 128 +- module/todo/control.php | 504 +- module/todo/lang/en.php | 156 +- module/todo/lang/zh-cn.php | 156 +- module/todo/lang/zh-tw.php | 156 +- module/todo/model.php | 856 +- module/todo/view/create.html.php | 122 +- module/todo/view/edit.html.php | 134 +- module/todo/view/export.html.php | 26 +- module/todo/view/view.html.php | 174 +- module/tree/control.php | 474 +- module/tree/lang/en.php | 80 +- module/tree/lang/zh-cn.php | 80 +- module/tree/lang/zh-tw.php | 80 +- module/tree/model.php | 1094 +- module/tree/view/browse.html.php | 192 +- module/tree/view/edit.html.php | 76 +- module/upgrade/control.php | 162 +- module/upgrade/lang/en.php | 122 +- module/upgrade/lang/zh-cn.php | 122 +- module/upgrade/lang/zh-tw.php | 122 +- module/upgrade/model.php | 2414 ++-- module/upgrade/view/confirm.html.php | 52 +- module/upgrade/view/execute.html.php | 60 +- module/upgrade/view/index.html.php | 44 +- module/upgrade/view/selectversion.html.php | 58 +- module/user/control.php | 1012 +- module/user/lang/en.php | 164 +- module/user/lang/zh-cn.php | 164 +- module/user/lang/zh-tw.php | 164 +- module/user/model.php | 822 +- module/user/view/bug.html.php | 86 +- module/user/view/create.html.php | 114 +- module/user/view/deny.html.php | 62 +- module/user/view/dynamic.html.php | 116 +- module/user/view/edit.html.php | 186 +- module/user/view/login.html.php | 100 +- module/user/view/profile.html.php | 238 +- module/user/view/project.html.php | 92 +- module/user/view/story.html.php | 30 +- module/user/view/task.html.php | 88 +- module/user/view/team.html.php | 28 +- module/user/view/todo.html.php | 120 +- module/user/view/view.html.php | 156 +- www/index.php | 86 +- www/install.php | 76 +- www/upgrade.php | 74 +- 389 files changed, 55211 insertions(+), 55211 deletions(-) diff --git a/bin/initext.php b/bin/initext.php index c2dc053dbe..22dc544af0 100644 --- a/bin/initext.php +++ b/bin/initext.php @@ -1,60 +1,60 @@ - - * @package common - * @version $Id$ - * @link http://www.zentao.net - */ -include '../config/config.php'; - -$modules = array(); -$moduleRoot = realpath('../module/') . '/'; - -if(is_dir($moduleRoot)) -{ - if($dh = opendir($moduleRoot)) - { - while($module = readdir($dh)) - { - if(strpos(basename($module), '.') === false) $modules[] = $module; - } - closedir($dh); - } -} -else -{ - die("The module you input does not exist. \n"); -} - -foreach($modules as $module) -{ - /* 设定各个目录。*/ - $extRoot = $moduleRoot . DIRECTORY_SEPARATOR. $module . DIRECTORY_SEPARATOR . 'ext'; - $extControl = $extRoot . DIRECTORY_SEPARATOR . 'control'; - $extModel = $extRoot . DIRECTORY_SEPARATOR . 'model'; - $extView = $extRoot . DIRECTORY_SEPARATOR . 'view'; - $extConfig = $extRoot . DIRECTORY_SEPARATOR . 'config'; - $extLang = $extRoot . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR; - - /* 建立各个扩展目录 */ - if(!file_exists($extRoot)) mkdir($extRoot, 0777); - if(!file_exists($extControl)) mkdir($extControl, 0777); - if(!file_exists($extModel)) mkdir($extModel, 0777); - if(!file_exists($extView)) mkdir($extView, 0777); - if(!file_exists($extConfig)) mkdir($extConfig, 0777); - if(!file_exists($extLang)) mkdir($extLang, 0777); - - /* 创建语言目录。*/ - $langs = array_keys($config->langs); - foreach($langs as $lang) - { - $langPath = $extLang . $lang; - if(!file_exists($langPath)) mkdir($langPath, 0777); - } - - echo "init $module ... \n"; -} + + * @package common + * @version $Id$ + * @link http://www.zentao.net + */ +include '../config/config.php'; + +$modules = array(); +$moduleRoot = realpath('../module/') . '/'; + +if(is_dir($moduleRoot)) +{ + if($dh = opendir($moduleRoot)) + { + while($module = readdir($dh)) + { + if(strpos(basename($module), '.') === false) $modules[] = $module; + } + closedir($dh); + } +} +else +{ + die("The module you input does not exist. \n"); +} + +foreach($modules as $module) +{ + /* 设定各个目录。*/ + $extRoot = $moduleRoot . DIRECTORY_SEPARATOR. $module . DIRECTORY_SEPARATOR . 'ext'; + $extControl = $extRoot . DIRECTORY_SEPARATOR . 'control'; + $extModel = $extRoot . DIRECTORY_SEPARATOR . 'model'; + $extView = $extRoot . DIRECTORY_SEPARATOR . 'view'; + $extConfig = $extRoot . DIRECTORY_SEPARATOR . 'config'; + $extLang = $extRoot . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR; + + /* 建立各个扩展目录 */ + if(!file_exists($extRoot)) mkdir($extRoot, 0777); + if(!file_exists($extControl)) mkdir($extControl, 0777); + if(!file_exists($extModel)) mkdir($extModel, 0777); + if(!file_exists($extView)) mkdir($extView, 0777); + if(!file_exists($extConfig)) mkdir($extConfig, 0777); + if(!file_exists($extLang)) mkdir($extLang, 0777); + + /* 创建语言目录。*/ + $langs = array_keys($config->langs); + foreach($langs as $lang) + { + $langPath = $extLang . $lang; + if(!file_exists($langPath)) mkdir($langPath, 0777); + } + + echo "init $module ... \n"; +} diff --git a/build/windows/uniserver/home/admin/www/includes/lang/Chinese.php b/build/windows/uniserver/home/admin/www/includes/lang/Chinese.php index 9d7a165784..0eaac58ef9 100644 --- a/build/windows/uniserver/home/admin/www/includes/lang/Chinese.php +++ b/build/windows/uniserver/home/admin/www/includes/lang/Chinese.php @@ -1,411 +1,411 @@ - 'Uniform Server', - 'apanel' => '管理面板', - 'dev-team' => 'The Uniform Server Development Team', - - //-------------------------------------------------------------------------------------------- - // Source Code - //-------------------------------------------------------------------------------------------- - - 'code-show' => '查看源代码', - 'code-source' => '查看源代码', - 'code-back' => '关闭查看', - - //-------------------------------------------------------------------------------------------- - // Navigation - //-------------------------------------------------------------------------------------------- - - // Basic - 'nav-home' => '主页', - 'nav-web' => 'Uniform Server Website', - 'nav-secure' => '服务器安全性', - 'nav-phpinfo' => 'PHP信息', - 'nav-cgienv' => 'Perl环境', - 'nav-status' => 'Apache运行状态', - 'nav-info' => 'Apache信息', - 'nav-update' => '检查更新', - // Server Control - 'nav-start' => '服务器控制面板', - // Server Control - Service - 'nav-uservers' => '卸载服务', - 'nav-rapaches' => '重新启动Apache服务', - 'nav-rmysqls' => '重新启动MySQL服务', - // Server Control - Standard Program - 'nav-sserver' => '关闭所有服务', - 'nav-rmysql' => '运行MySQL', - 'nav-smysql' => '关闭MySQL', - // 配置s - 'nav-config' => '配置', - 'nav-aconfig' => 'Apache 配置', - 'nav-pconfig' => 'PHP 配置', - 'nav-vhost' => '管理虚拟机', - 'nav-apsetup' => '管理面板配置', - 'nav-psetup' => 'Private Server 配置', - 'nav-sslpsetup' => 'Private Secure Server Config', - 'nav-mqsetup' => 'MySQL Server 配置', - - // Tools Navigation - 'nav-tools' => '工具', - 'nav-pma' => 'phpMyAdmin', - 'nav-elog' => '错误日志查看器', - 'nav-u2w' => 'windows到unix转换器', - 'nav-smig' => 'Server Migration', - 'nav-key' => '服务器私钥和证书生成', - 'nav-mysqlrestore' => '重置MySQL密码', - - // Plugins Navigation - 'nav-plugins' => '插件管理', - 'nav-pear' => '安装Pear', - 'nav-eaccelerator' => 'eAccelerator控制面板', - // Misc Navigation - 'nav-misc' => '其他杂项', - 'nav-sup' => '在线支持', - // Documentation - 'nav-docs1' => '文档', - 'nav-sdoc' => '本机文档', - 'nav-docs2' => '在线文档', - 'nav-udoc' => '用户指南', - 'nav-wiki' => 'WIKI', - 'nav-phdoc' => 'PHP文档', - 'nav-mydoc' => 'MySQL文档', - 'nav-pedoc' => 'Perl文档', - // Languages - 'nav-langs' => 'Languages', - - //-------------------------------------------------------------------------------------------- - // Home - //-------------------------------------------------------------------------------------------- - - 'main-head' => '管理面板'. $us_apanel_version .'', - 'main-text' => ' - 欢迎使用 Uniform Server '. $us_version .'!.
- 您现在访问的是管理面板,通过它你可以控制你的Apache、PHP、MySQL服务。虽然我们一直持续的为它增加新的功能,改进,并修复Bug,但它是稳定并且功能完整的,使用起来也非常的简单友好。 -
- 如果发现了Bug,请反馈给我们:forum. -
-
- 鸣谢: -
- Uniform Server开发团队', - 'main-secure' => '系统安全检查列表', - 'main-text-0' => '修改管理面板的用户名和密码点击这里', - 'main-text-1' => 'Change the username/password for the server 点击这里', - 'main-text-2' => 'Change the root password for mysql by editing 点击这里', - 'main-text-3' => 'Run the Security Console and see if everything is OK.', - 'main-text-4' => 'Change the username/password for the SSL server 点击这里', - - //-------------------------------------------------------------------------------------------- - // Update - //-------------------------------------------------------------------------------------------- - - 'update-head' => 'Uniform Server Version Check', - 'update-check' => 'Checking Version...', - 'update-notfound' => ' - Version file could not be found on the Uniform Server! -
- Or -
- The Unifrom Server is off-line! -
- Or -
- You are not connected to the Internet! -
', - - 'update-true' => ' - Installed version of the Uniform Server is the latest one. -
- You don\'t need to update it. -
', - 'update-false' => 'A Newer version of the Uniform Server is available!', - 'update-new' => 'New Version', - 'update-yours' => 'Installed Version', - 'update-get' => 'You can get the newer version from our website by clicking the link below.', - - //-------------------------------------------------------------------------------------------- - // Server Control - Standard program - //-------------------------------------------------------------------------------------------- - - 'server-stop-head1' => 'Stop Servers', - 'server-stop-head2' => 'Stopping servers', - 'server-stop-txt1' => 'This script will stop Apache and MySQL servers', - 'server-stop-txt2' => 'The Servers are stopping please wait for a beep to confirm!', - 'server-stop-txt3' => 'Thank you for using The Uniform Server.', - 'server-confirm-button' => 'Confirm', - - 'start-mysql-head1' => 'Start MySQL Server', - 'start-mysql-head2' => 'Starting the MySQL server.', - 'start-mysql-txt1' => 'This script will start the MySQL server.', - 'start-mysql-txt2' => 'MySQL server already running.', - 'start-mysql-txt3' => 'The MySQL server was started you can continue using the server.', - 'start-mysql-button' => 'Start MySQL Server', - - 'stop-mysql-head1' => 'Stop MySQL Server', - 'stop-mysql-head2' => 'Stopping the MySQL server.', - 'stop-mysql-txt1' => 'This script will stop the MySQL server.', - 'stop-mysql-txt2' => 'The MySQL server was stopped.', - 'stop-mysql-txt3' => 'MySQL server not running.', - 'stop-mysql-button' => 'Stop MySQL Server', - - //-------------------------------------------------------------------------------------------- - // Server Control - Services - //-------------------------------------------------------------------------------------------- - - 'service-apache-head1' => 'Restart Apache Service', - 'service-apache-head2' => 'Restarting Apache service', - 'service-apache-txt1' => 'This script will restart the Apache service.', - 'service-apache-txt2' => 'It will take a some time', - 'service-apache-txt3' => 'The Apache service is restarting please wait
Between 2-10 seconds!' , - 'service-apache-txt4' => 'Apanel will reload to reflect any server configuration changes.', - - 'service-mysql-head1' => 'Restart MySQL Service', - 'service-mysql-head2' => 'The MySQL service was restarted.', - 'service-mysql-txt1' => 'This script will restart the MySQL service.', - 'service-mysql-txt2' => 'It will take some time', - 'service-mysql-txt3' => 'The MySQL service was restarted you can continue using the server.', - - 'service-confirm-button' => 'Confirm', - - //-------------------------------------------------------------------------------------------- - // Apache 配置 - //-------------------------------------------------------------------------------------------- - - 'aconfig-head' => 'Apache 配置', - 'aconfig-conf' => 'Configure Apache', - 'aconfig-sname' => 'Server Name', - 'aconfig-wemail' => 'Server Admin Email', - 'aconfig-difiles' => 'Directory Index Files', - 'aconfig-ssi' => 'Server Side Includes', - 'aconfig-ssig' => 'Server Signature', - 'aconfig-listen' => 'Listen', - 'aconfig-text-0' => 'something', - 'aconfig-text-1' => ' - The changes have been successfully saved.
Changes will take effect after server restart!', - 'aconfig-save' => 'Save', - 'aconfig-module' => 'At the moment PHP is loaded as Apache module.', - 'aconfig-cgi' => 'At the moment PHP scripts are executed though Apache CGI interface.', - 'aconfig-help' => '?', - - //-------------------------------------------------------------------------------------------- - // PHP 配置 - //-------------------------------------------------------------------------------------------- - - 'pconfig-head' => 'PHP 配置', - 'pconfig-conf' => 'Configure PHP', - 'pconfig-smode' => 'Safe Mode', - 'pconfig-rg' => 'Register Globals', - 'pconfig-mtexec' => 'Maximum Script Execute Time (s.)', - 'pconfig-mmexec' => 'Maximum Memory Amount (MB)', - 'pconfig-ssig' => 'Show PHP In Server Signature', - 'pconfig-perror' => 'Print Errors', - 'pconfig-mpsize' => 'Maximum Post Size', - 'pconfig-musize' => 'Maximum Upload Size', - 'pconfig-text-0' => 'something', - 'pconfig-text-1' => ' - The changes have been successfully saved.
Changes will take effect after server restart!', - 'pconfig-save' => 'Save', - 'pconfig-module' => 'At the moment PHP is loaded as Apache module.', - 'pconfig-cgi' => 'At the moment PHP scripts are executed though Apache CGI interface.', - 'pconfig-help' => '?', - - //-------------------------------------------------------------------------------------------- - // VHost Manager - //-------------------------------------------------------------------------------------------- - - 'vhost-head' => 'Virtual Host', - 'vhost-setup' => 'Virtual Host Setup', - 'vhost-settings' => 'Virtual Host Settings', - 'vhost-text-0' => 'You have', - 'vhost-text-1' => 'hosts in your httpd.conf file:', - 'vhost-text-2' => 'Error in hosts file:', - 'vhost-text-3' => 'All hostnames exist in hosts file!', - 'vhost-new' => ' - Use this new and cool tool to add more virtual hosts to your server without having to edit - the httpd.conf file yourself.', - 'vhost-new-ex' => '(ex. newhost.localhost)', - 'vhost-name' => 'Name:', - 'vhost-path' => 'Path to DocumentRoot:', - 'vhost-path-ex' => '(ex. c:/www/newhost)', - 'vhost-opt' => 'Optional additions:', - 'vhost-opt-ex' => '(ex. error_log etc.)', - 'vhost-dne' => 'does not exist', - 'vhost-make' => 'Create VHost', - 'vhost-error-1' => 'Error in path to your hosts-file!', - 'vhost-error-2' => 'Error in path to your httpd.conf!', - 'vhost-text-4' => 'Safe_mode is On, so restart Apache manually!', - 'vhost-credit' => 'Script By Sukos', - - //-------------------------------------------------------------------------------------------- - // Error Log Viewer - //-------------------------------------------------------------------------------------------- - - 'elog-viewer-head1' => 'Error Log Viewer', - 'elog-viewer-head2' => 'Viewing Error Log File', - - //-------------------------------------------------------------------------------------------- - // Win to Unix Converter - //-------------------------------------------------------------------------------------------- - - 'w2u-head1' => 'Windows to Unix Converter', - 'w2u-head2' => 'Convert Windows Perl Files', - 'w2u-head3' => 'Converted Windows Perl Files', - - 'w2u-txt1' => 'If you have problems executing your cgi scripts on Unix.
- This program will convert cgi scripts from Windows to Unix format Dec(#10#13=>#13).
Hex 0D0A to 0A', - - 'w2u-txt2' => 'Instruction:
After execution you can pick up scripts ready for execution - on a Unix machine from the \\cgi-bin-unix\\ directory.
', - - 'w2u-txt3' => 'Files converted:
They are located in folder \\cgi-bin-unix\\ ', - - 'w2u-convert-button' => 'Convert', - - - //-------------------------------------------------------------------------------------------- - // Server Certificate and Key Generation - //-------------------------------------------------------------------------------------------- - - 'cert-head1' => 'Server Certificate and Key Generation', - 'cert-head2' => 'Verify Generation', - 'cert-head3' => 'Unable to run Certificate and Key Generation.', - 'cert-head4' => 'Certificate and Key Generation Complete.', - - 'cert-txt1' => 'Click on Generate! and follow instructions.', - 'cert-txt2' => 'Services are not allowed to interact with the desktop.
You need to run this script manually:', - 'cert-txt3' => 'Alternatively use UniTray.', - 'cert-txt4' => 'Cirtificate location:', - 'cert-txt5' => 'Key location:', - - 'cert-confirm-button' => 'Generate', - - //-------------------------------------------------------------------------------------------- - // MySQL restore password - //-------------------------------------------------------------------------------------------- - - 'mysql-head1' => 'MySQL restore password', - 'mysql-head2' => 'Verify Restore', - 'mysql-head3' => 'MySQL password restored.', - - 'mysql-txt1' => 'Click on Restore! Restore will take several seconds.', - 'mysql-txt2' => 'Password restored you can continue using the server..', - - 'mysql-confirm-button' => 'Restore MySQL Password', - - //-------------------------------------------------------------------------------------------- - // Server Security Console - //-------------------------------------------------------------------------------------------- - - 'secure1-head' => 'Security Alert!', - 'secure1-sub' => 'Possible Attack', - 'secure1-text-0' => 'IP ADDRESS is not 127.0.0.1, but', - 'secure1-text-1' => 'Note: HTTP_REFERER is', - 'secure1-text-2' => 'To disable this warning set $unisecure to 0 in: /home/admin/www/includes/config.inc.php', - - //-------------------------------------------------------------------------------------------- - // Admin Panel Setup - //-------------------------------------------------------------------------------------------- - - 'apsetup-head' => 'Admin Panel 配置', - 'apsetup-sub-0' => 'User Management', - 'apsetup-text-0' => 'Setup the username and password for the Admin Panel here. Please note that you might have - to activate this feature in the /home/admin/www/.htaccess file.', - 'apsetup-user' => 'Username', - 'apsetup-pass' => 'Password', - 'apsetup-change' => 'Change', - 'apsetup-success' => 'The Admin Panel username/password has been changed to the new values:', - - //-------------------------------------------------------------------------------------------- - // Private Server Setup - //-------------------------------------------------------------------------------------------- - - 'psetup-head' => 'Private Server 配置', - 'psetup-sub-0' => 'User Management', - 'psetup-text-0' => 'Setup the username and password for your Private Server here. Please note that you might have - to activate this feature in the /www/.htaccess file.', - 'psetup-user' => 'Username', - 'psetup-pass' => 'Password', - 'psetup-change' => 'Change', - 'psetup-success' => 'Your Private Server username/password has been changed to the new values:', - - //-------------------------------------------------------------------------------------------- - // Private Secure Server Setup (SSL) - //-------------------------------------------------------------------------------------------- - - 'sslpsetup-head' => 'Private Secure Server 配置 (SSL)', - 'sslpsetup-sub-0' => 'User Management', - 'sslpsetup-text-0' => 'Setup the username and password for your Private Secure Server here. Please note that you might have - to activate this feature in the /ssl/.htaccess file.', - 'sslpsetup-user' => 'Username', - 'sslpsetup-pass' => 'Password', - 'sslpsetup-change' => 'Change', - 'sslpsetup-success' => 'Your Private Secure Server username/password has been changed to the new values:', - - //-------------------------------------------------------------------------------------------- - // MySQL Setup - //-------------------------------------------------------------------------------------------- - - 'mqsetup-head' => 'MySQL Server 配置', - 'mqsetup-sub-0' => 'User Management', - 'mqsetup-text-0' => 'Setup the MySQL password here. After changing the MySQL password, please note that you - must shutdown the server using the Stop.bat file and then start the server over again.', - 'mqsetup-pass' => 'MySQL Password', - 'mqsetup-change' => 'Change', - 'mqsetup-success' => 'Your MySQL password has been changed to the new value:', - - //-------------------------------------------------------------------------------------------- - // Server Security Center - //-------------------------------------------------------------------------------------------- - - 'secure-head' => 'Security Center', - 'secure-sub-0' => 'User Management Security', - 'secure-sub-1' => 'Server Security', - 'secure-text-0' => 'This part of the security center will check all user management settings to make sure that - everything is set. It will tell you if something needs to be changed.', - 'secure-text-1' => 'SECURITY MSG', - 'secure-text-2' => 'STATUS', - 'secure-text-3' => 'Admin Panel', - 'secure-text-X' => 'If the username/password is still set to root, then you probably need to change this - by clicking the UNSECURE link.', - 'secure-text-sslX' => 'Unsecure indicates you do not have a server certificate or key. Create new ones by clicking the UNSECURE link.', - 'secure-secure' => 'SECURE', - 'secure-unsecure' => 'UNSECURE', - 'secure-text-7' => 'If the password is still set to root, then you probably need to change this by clicking the UNSECURE link.', - 'secure-text-8' => 'This part of the security center will check and make sure the server settings are appropriate and set corectly.', - 'secure-text-9' => 'PHP Safe Mode', - 'secure-text-10' => 'This checks to see if PHP is running in SAFE MODE. Now, PHP does not have to run in SAFE MODE, but - if you want the extra security, you can set it by clicking on the UNSECURE link.', - 'secure-text-p' => 'Personal Server', - 'secure-text-sslp' => 'Personal Secure Server (SSL)', - 'secure-text-sslcertp' => 'Server Certificate and Key (SSL)', - 'secure-text-s' => 'MySQL Server', - 'secure-text-11' => 'Admin Panel Access', - 'secure-text-12' => 'Server Access', - 'secure-text-12ssl' => 'Server Access (SSL)', - 'secure-text-13' => 'While this is another feature that is not throughly important as other features are in place against - outside access to the Admin Panel, this checks to see if your Admin Panel is secured using the Auth method. Please change this - by editing the '.$us_apanel.'/.htaccess file.', - 'secure-text-14' => 'If you are running your server in Production Mode, Skip this one. If not and you would like to - add more security to the server by blocking it using the Auth method, then change this in by editing the '.$us_www.'/.htaccess file.', - 'secure-text-14ssl' => 'If you are running your server in Production Mode, Skip this one. If not and you would like to - add more security to the server by blocking it using the Auth method, then change this in by editing the '.$us_ssl.'/.htaccess file.', - 'secure-view' => 'Local View', - 'secure-look' => 'Due to the fact that some PC\'s have a different hostname set rather than localhost, we use the IP method here. This - checks to make sure that you are viewing the Admin Panel (this) from local.', -); - -# Beta Feature, Currently For Debugging Only -#array2table($US, true); -?> + 'Uniform Server', + 'apanel' => '管理面板', + 'dev-team' => 'The Uniform Server Development Team', + + //-------------------------------------------------------------------------------------------- + // Source Code + //-------------------------------------------------------------------------------------------- + + 'code-show' => '查看源代码', + 'code-source' => '查看源代码', + 'code-back' => '关闭查看', + + //-------------------------------------------------------------------------------------------- + // Navigation + //-------------------------------------------------------------------------------------------- + + // Basic + 'nav-home' => '主页', + 'nav-web' => 'Uniform Server Website', + 'nav-secure' => '服务器安全性', + 'nav-phpinfo' => 'PHP信息', + 'nav-cgienv' => 'Perl环境', + 'nav-status' => 'Apache运行状态', + 'nav-info' => 'Apache信息', + 'nav-update' => '检查更新', + // Server Control + 'nav-start' => '服务器控制面板', + // Server Control - Service + 'nav-uservers' => '卸载服务', + 'nav-rapaches' => '重新启动Apache服务', + 'nav-rmysqls' => '重新启动MySQL服务', + // Server Control - Standard Program + 'nav-sserver' => '关闭所有服务', + 'nav-rmysql' => '运行MySQL', + 'nav-smysql' => '关闭MySQL', + // 配置s + 'nav-config' => '配置', + 'nav-aconfig' => 'Apache 配置', + 'nav-pconfig' => 'PHP 配置', + 'nav-vhost' => '管理虚拟机', + 'nav-apsetup' => '管理面板配置', + 'nav-psetup' => 'Private Server 配置', + 'nav-sslpsetup' => 'Private Secure Server Config', + 'nav-mqsetup' => 'MySQL Server 配置', + + // Tools Navigation + 'nav-tools' => '工具', + 'nav-pma' => 'phpMyAdmin', + 'nav-elog' => '错误日志查看器', + 'nav-u2w' => 'windows到unix转换器', + 'nav-smig' => 'Server Migration', + 'nav-key' => '服务器私钥和证书生成', + 'nav-mysqlrestore' => '重置MySQL密码', + + // Plugins Navigation + 'nav-plugins' => '插件管理', + 'nav-pear' => '安装Pear', + 'nav-eaccelerator' => 'eAccelerator控制面板', + // Misc Navigation + 'nav-misc' => '其他杂项', + 'nav-sup' => '在线支持', + // Documentation + 'nav-docs1' => '文档', + 'nav-sdoc' => '本机文档', + 'nav-docs2' => '在线文档', + 'nav-udoc' => '用户指南', + 'nav-wiki' => 'WIKI', + 'nav-phdoc' => 'PHP文档', + 'nav-mydoc' => 'MySQL文档', + 'nav-pedoc' => 'Perl文档', + // Languages + 'nav-langs' => 'Languages', + + //-------------------------------------------------------------------------------------------- + // Home + //-------------------------------------------------------------------------------------------- + + 'main-head' => '管理面板'. $us_apanel_version .'', + 'main-text' => ' + 欢迎使用 Uniform Server '. $us_version .'!.
+ 您现在访问的是管理面板,通过它你可以控制你的Apache、PHP、MySQL服务。虽然我们一直持续的为它增加新的功能,改进,并修复Bug,但它是稳定并且功能完整的,使用起来也非常的简单友好。 +
+ 如果发现了Bug,请反馈给我们:forum. +
+
+ 鸣谢: +
+ Uniform Server开发团队', + 'main-secure' => '系统安全检查列表', + 'main-text-0' => '修改管理面板的用户名和密码点击这里', + 'main-text-1' => 'Change the username/password for the server 点击这里', + 'main-text-2' => 'Change the root password for mysql by editing 点击这里', + 'main-text-3' => 'Run the Security Console and see if everything is OK.', + 'main-text-4' => 'Change the username/password for the SSL server 点击这里', + + //-------------------------------------------------------------------------------------------- + // Update + //-------------------------------------------------------------------------------------------- + + 'update-head' => 'Uniform Server Version Check', + 'update-check' => 'Checking Version...', + 'update-notfound' => ' + Version file could not be found on the Uniform Server! +
+ Or +
+ The Unifrom Server is off-line! +
+ Or +
+ You are not connected to the Internet! +
', + + 'update-true' => ' + Installed version of the Uniform Server is the latest one. +
+ You don\'t need to update it. +
', + 'update-false' => 'A Newer version of the Uniform Server is available!', + 'update-new' => 'New Version', + 'update-yours' => 'Installed Version', + 'update-get' => 'You can get the newer version from our website by clicking the link below.', + + //-------------------------------------------------------------------------------------------- + // Server Control - Standard program + //-------------------------------------------------------------------------------------------- + + 'server-stop-head1' => 'Stop Servers', + 'server-stop-head2' => 'Stopping servers', + 'server-stop-txt1' => 'This script will stop Apache and MySQL servers', + 'server-stop-txt2' => 'The Servers are stopping please wait for a beep to confirm!', + 'server-stop-txt3' => 'Thank you for using The Uniform Server.', + 'server-confirm-button' => 'Confirm', + + 'start-mysql-head1' => 'Start MySQL Server', + 'start-mysql-head2' => 'Starting the MySQL server.', + 'start-mysql-txt1' => 'This script will start the MySQL server.', + 'start-mysql-txt2' => 'MySQL server already running.', + 'start-mysql-txt3' => 'The MySQL server was started you can continue using the server.', + 'start-mysql-button' => 'Start MySQL Server', + + 'stop-mysql-head1' => 'Stop MySQL Server', + 'stop-mysql-head2' => 'Stopping the MySQL server.', + 'stop-mysql-txt1' => 'This script will stop the MySQL server.', + 'stop-mysql-txt2' => 'The MySQL server was stopped.', + 'stop-mysql-txt3' => 'MySQL server not running.', + 'stop-mysql-button' => 'Stop MySQL Server', + + //-------------------------------------------------------------------------------------------- + // Server Control - Services + //-------------------------------------------------------------------------------------------- + + 'service-apache-head1' => 'Restart Apache Service', + 'service-apache-head2' => 'Restarting Apache service', + 'service-apache-txt1' => 'This script will restart the Apache service.', + 'service-apache-txt2' => 'It will take a some time', + 'service-apache-txt3' => 'The Apache service is restarting please wait
Between 2-10 seconds!' , + 'service-apache-txt4' => 'Apanel will reload to reflect any server configuration changes.', + + 'service-mysql-head1' => 'Restart MySQL Service', + 'service-mysql-head2' => 'The MySQL service was restarted.', + 'service-mysql-txt1' => 'This script will restart the MySQL service.', + 'service-mysql-txt2' => 'It will take some time', + 'service-mysql-txt3' => 'The MySQL service was restarted you can continue using the server.', + + 'service-confirm-button' => 'Confirm', + + //-------------------------------------------------------------------------------------------- + // Apache 配置 + //-------------------------------------------------------------------------------------------- + + 'aconfig-head' => 'Apache 配置', + 'aconfig-conf' => 'Configure Apache', + 'aconfig-sname' => 'Server Name', + 'aconfig-wemail' => 'Server Admin Email', + 'aconfig-difiles' => 'Directory Index Files', + 'aconfig-ssi' => 'Server Side Includes', + 'aconfig-ssig' => 'Server Signature', + 'aconfig-listen' => 'Listen', + 'aconfig-text-0' => 'something', + 'aconfig-text-1' => ' + The changes have been successfully saved.
Changes will take effect after server restart!', + 'aconfig-save' => 'Save', + 'aconfig-module' => 'At the moment PHP is loaded as Apache module.', + 'aconfig-cgi' => 'At the moment PHP scripts are executed though Apache CGI interface.', + 'aconfig-help' => '?', + + //-------------------------------------------------------------------------------------------- + // PHP 配置 + //-------------------------------------------------------------------------------------------- + + 'pconfig-head' => 'PHP 配置', + 'pconfig-conf' => 'Configure PHP', + 'pconfig-smode' => 'Safe Mode', + 'pconfig-rg' => 'Register Globals', + 'pconfig-mtexec' => 'Maximum Script Execute Time (s.)', + 'pconfig-mmexec' => 'Maximum Memory Amount (MB)', + 'pconfig-ssig' => 'Show PHP In Server Signature', + 'pconfig-perror' => 'Print Errors', + 'pconfig-mpsize' => 'Maximum Post Size', + 'pconfig-musize' => 'Maximum Upload Size', + 'pconfig-text-0' => 'something', + 'pconfig-text-1' => ' + The changes have been successfully saved.
Changes will take effect after server restart!', + 'pconfig-save' => 'Save', + 'pconfig-module' => 'At the moment PHP is loaded as Apache module.', + 'pconfig-cgi' => 'At the moment PHP scripts are executed though Apache CGI interface.', + 'pconfig-help' => '?', + + //-------------------------------------------------------------------------------------------- + // VHost Manager + //-------------------------------------------------------------------------------------------- + + 'vhost-head' => 'Virtual Host', + 'vhost-setup' => 'Virtual Host Setup', + 'vhost-settings' => 'Virtual Host Settings', + 'vhost-text-0' => 'You have', + 'vhost-text-1' => 'hosts in your httpd.conf file:', + 'vhost-text-2' => 'Error in hosts file:', + 'vhost-text-3' => 'All hostnames exist in hosts file!', + 'vhost-new' => ' + Use this new and cool tool to add more virtual hosts to your server without having to edit + the httpd.conf file yourself.', + 'vhost-new-ex' => '(ex. newhost.localhost)', + 'vhost-name' => 'Name:', + 'vhost-path' => 'Path to DocumentRoot:', + 'vhost-path-ex' => '(ex. c:/www/newhost)', + 'vhost-opt' => 'Optional additions:', + 'vhost-opt-ex' => '(ex. error_log etc.)', + 'vhost-dne' => 'does not exist', + 'vhost-make' => 'Create VHost', + 'vhost-error-1' => 'Error in path to your hosts-file!', + 'vhost-error-2' => 'Error in path to your httpd.conf!', + 'vhost-text-4' => 'Safe_mode is On, so restart Apache manually!', + 'vhost-credit' => 'Script By Sukos', + + //-------------------------------------------------------------------------------------------- + // Error Log Viewer + //-------------------------------------------------------------------------------------------- + + 'elog-viewer-head1' => 'Error Log Viewer', + 'elog-viewer-head2' => 'Viewing Error Log File', + + //-------------------------------------------------------------------------------------------- + // Win to Unix Converter + //-------------------------------------------------------------------------------------------- + + 'w2u-head1' => 'Windows to Unix Converter', + 'w2u-head2' => 'Convert Windows Perl Files', + 'w2u-head3' => 'Converted Windows Perl Files', + + 'w2u-txt1' => 'If you have problems executing your cgi scripts on Unix.
+ This program will convert cgi scripts from Windows to Unix format Dec(#10#13=>#13).
Hex 0D0A to 0A', + + 'w2u-txt2' => 'Instruction:
After execution you can pick up scripts ready for execution + on a Unix machine from the \\cgi-bin-unix\\ directory.
', + + 'w2u-txt3' => 'Files converted:
They are located in folder \\cgi-bin-unix\\ ', + + 'w2u-convert-button' => 'Convert', + + + //-------------------------------------------------------------------------------------------- + // Server Certificate and Key Generation + //-------------------------------------------------------------------------------------------- + + 'cert-head1' => 'Server Certificate and Key Generation', + 'cert-head2' => 'Verify Generation', + 'cert-head3' => 'Unable to run Certificate and Key Generation.', + 'cert-head4' => 'Certificate and Key Generation Complete.', + + 'cert-txt1' => 'Click on Generate! and follow instructions.', + 'cert-txt2' => 'Services are not allowed to interact with the desktop.
You need to run this script manually:', + 'cert-txt3' => 'Alternatively use UniTray.', + 'cert-txt4' => 'Cirtificate location:', + 'cert-txt5' => 'Key location:', + + 'cert-confirm-button' => 'Generate', + + //-------------------------------------------------------------------------------------------- + // MySQL restore password + //-------------------------------------------------------------------------------------------- + + 'mysql-head1' => 'MySQL restore password', + 'mysql-head2' => 'Verify Restore', + 'mysql-head3' => 'MySQL password restored.', + + 'mysql-txt1' => 'Click on Restore! Restore will take several seconds.', + 'mysql-txt2' => 'Password restored you can continue using the server..', + + 'mysql-confirm-button' => 'Restore MySQL Password', + + //-------------------------------------------------------------------------------------------- + // Server Security Console + //-------------------------------------------------------------------------------------------- + + 'secure1-head' => 'Security Alert!', + 'secure1-sub' => 'Possible Attack', + 'secure1-text-0' => 'IP ADDRESS is not 127.0.0.1, but', + 'secure1-text-1' => 'Note: HTTP_REFERER is', + 'secure1-text-2' => 'To disable this warning set $unisecure to 0 in: /home/admin/www/includes/config.inc.php', + + //-------------------------------------------------------------------------------------------- + // Admin Panel Setup + //-------------------------------------------------------------------------------------------- + + 'apsetup-head' => 'Admin Panel 配置', + 'apsetup-sub-0' => 'User Management', + 'apsetup-text-0' => 'Setup the username and password for the Admin Panel here. Please note that you might have + to activate this feature in the /home/admin/www/.htaccess file.', + 'apsetup-user' => 'Username', + 'apsetup-pass' => 'Password', + 'apsetup-change' => 'Change', + 'apsetup-success' => 'The Admin Panel username/password has been changed to the new values:', + + //-------------------------------------------------------------------------------------------- + // Private Server Setup + //-------------------------------------------------------------------------------------------- + + 'psetup-head' => 'Private Server 配置', + 'psetup-sub-0' => 'User Management', + 'psetup-text-0' => 'Setup the username and password for your Private Server here. Please note that you might have + to activate this feature in the /www/.htaccess file.', + 'psetup-user' => 'Username', + 'psetup-pass' => 'Password', + 'psetup-change' => 'Change', + 'psetup-success' => 'Your Private Server username/password has been changed to the new values:', + + //-------------------------------------------------------------------------------------------- + // Private Secure Server Setup (SSL) + //-------------------------------------------------------------------------------------------- + + 'sslpsetup-head' => 'Private Secure Server 配置 (SSL)', + 'sslpsetup-sub-0' => 'User Management', + 'sslpsetup-text-0' => 'Setup the username and password for your Private Secure Server here. Please note that you might have + to activate this feature in the /ssl/.htaccess file.', + 'sslpsetup-user' => 'Username', + 'sslpsetup-pass' => 'Password', + 'sslpsetup-change' => 'Change', + 'sslpsetup-success' => 'Your Private Secure Server username/password has been changed to the new values:', + + //-------------------------------------------------------------------------------------------- + // MySQL Setup + //-------------------------------------------------------------------------------------------- + + 'mqsetup-head' => 'MySQL Server 配置', + 'mqsetup-sub-0' => 'User Management', + 'mqsetup-text-0' => 'Setup the MySQL password here. After changing the MySQL password, please note that you + must shutdown the server using the Stop.bat file and then start the server over again.', + 'mqsetup-pass' => 'MySQL Password', + 'mqsetup-change' => 'Change', + 'mqsetup-success' => 'Your MySQL password has been changed to the new value:', + + //-------------------------------------------------------------------------------------------- + // Server Security Center + //-------------------------------------------------------------------------------------------- + + 'secure-head' => 'Security Center', + 'secure-sub-0' => 'User Management Security', + 'secure-sub-1' => 'Server Security', + 'secure-text-0' => 'This part of the security center will check all user management settings to make sure that + everything is set. It will tell you if something needs to be changed.', + 'secure-text-1' => 'SECURITY MSG', + 'secure-text-2' => 'STATUS', + 'secure-text-3' => 'Admin Panel', + 'secure-text-X' => 'If the username/password is still set to root, then you probably need to change this + by clicking the UNSECURE link.', + 'secure-text-sslX' => 'Unsecure indicates you do not have a server certificate or key. Create new ones by clicking the UNSECURE link.', + 'secure-secure' => 'SECURE', + 'secure-unsecure' => 'UNSECURE', + 'secure-text-7' => 'If the password is still set to root, then you probably need to change this by clicking the UNSECURE link.', + 'secure-text-8' => 'This part of the security center will check and make sure the server settings are appropriate and set corectly.', + 'secure-text-9' => 'PHP Safe Mode', + 'secure-text-10' => 'This checks to see if PHP is running in SAFE MODE. Now, PHP does not have to run in SAFE MODE, but + if you want the extra security, you can set it by clicking on the UNSECURE link.', + 'secure-text-p' => 'Personal Server', + 'secure-text-sslp' => 'Personal Secure Server (SSL)', + 'secure-text-sslcertp' => 'Server Certificate and Key (SSL)', + 'secure-text-s' => 'MySQL Server', + 'secure-text-11' => 'Admin Panel Access', + 'secure-text-12' => 'Server Access', + 'secure-text-12ssl' => 'Server Access (SSL)', + 'secure-text-13' => 'While this is another feature that is not throughly important as other features are in place against + outside access to the Admin Panel, this checks to see if your Admin Panel is secured using the Auth method. Please change this + by editing the '.$us_apanel.'/.htaccess file.', + 'secure-text-14' => 'If you are running your server in Production Mode, Skip this one. If not and you would like to + add more security to the server by blocking it using the Auth method, then change this in by editing the '.$us_www.'/.htaccess file.', + 'secure-text-14ssl' => 'If you are running your server in Production Mode, Skip this one. If not and you would like to + add more security to the server by blocking it using the Auth method, then change this in by editing the '.$us_ssl.'/.htaccess file.', + 'secure-view' => 'Local View', + 'secure-look' => 'Due to the fact that some PC\'s have a different hostname set rather than localhost, we use the IP method here. This + checks to make sure that you are viewing the Admin Panel (this) from local.', +); + +# Beta Feature, Currently For Debugging Only +#array2table($US, true); +?> diff --git a/build/windows/xampp/build.php b/build/windows/xampp/build.php index bc6cc4a38f..9bbd1bd564 100644 --- a/build/windows/xampp/build.php +++ b/build/windows/xampp/build.php @@ -1,289 +1,289 @@ -removeDir('./xampp/anonymous'); -$file->removeDir('./xampp/cgi-bin'); -$file->removeDir('./xampp/contrib'); -$file->removeDir('./xampp/contrib'); -$file->removeDir('./xampp/install'); -$file->removeDir('./xampp/licenses'); -$file->removeDir('./xampp/nsi'); -$file->removeDir('./xampp/perl'); -$file->removeDir('./xampp/phpmyadmin'); -$file->removeDir('./xampp/sendmail'); -$file->removeDir('./xampp/security'); -$file->removeDir('./xampp/src'); -$file->batchRemoveFile('./xampp/tmp/*'); -$file->removeDir('./xampp/webdav'); -$file->removeDir('./xampp/setup_xampp.bat'); -$file->batchRemoveFile('./xampp/*.txt'); - -/* Process apache module. */ -$file->batchRemoveFile('./xampp/apache/*.txt'); -$file->batchRemoveFile('./xampp/apache/*.bat'); -$file->rename('./xampp/apache/modules', './xampp/apache/modulesold'); -$file->mkdir('./xampp/apache/modules'); - -$file->copyFile('./xampp/apache/modulesold/mod_auth_basic.so', './xampp/apache/modules/mod_auth_basic.so'); -$file->copyFile('./xampp/apache/modulesold/mod_mime_magic.so', './xampp/apache/modules/mod_mime_magic.so'); -$file->copyFile('./xampp/apache/modulesold/mod_mime.so', './xampp/apache/modules/mod_mime.so'); -$file->copyFile('./xampp/apache/modulesold/mod_expires.so', './xampp/apache/modules/mod_expires.so'); -$file->copyFile('./xampp/apache/modulesold/mod_env.so', './xampp/apache/modules/mod_env.so'); -$file->copyFile('./xampp/apache/modulesold/mod_rewrite.so', './xampp/apache/modules/mod_rewrite.so'); -$file->copyFile('./xampp/apache/modulesold/mod_vhost_alias.so','./xampp/apache/modules/mod_vhost_alias.so'); -$file->copyFile('./xampp/apache/modulesold/mod_setenvif.so', './xampp/apache/modules/mod_setenvif.so'); -$file->copyFile('./xampp/apache/modulesold/mod_autoindex.so', './xampp/apache/modules/mod_autoindex.so'); -$file->copyFile('./xampp/apache/modulesold/mod_authz_user.so', './xampp/apache/modules/mod_authz_user.so'); -$file->copyFile('./xampp/apache/modulesold/mod_authz_host.so', './xampp/apache/modules/mod_authz_host.so'); -$file->copyFile('./xampp/apache/modulesold/mod_alias.so', './xampp/apache/modules/mod_alias.so'); -$file->copyFile('./xampp/apache/modulesold/mod_dir.so', './xampp/apache/modules/mod_dir.so'); -$file->copyFile('./xampp/apache/modulesold/mod_deflate.so', './xampp/apache/modules/mod_deflate.so'); -$file->removeDir('./xampp/apache/modulesold'); - -/* Remove apache's error, icons, include, lib, logs directory. */ -$file->removeDir('./xampp/apache/error'); -$file->removeDir('./xampp/apache/icons'); -$file->removeDir('./xampp/apache/include'); -$file->removeDir('./xampp/apache/lib'); -$file->batchRemoveFile('./xampp/apache/logs/*.log'); - -$file->rename('./xampp/apache/bin', './xampp/apache/binold'); -$file->mkdir('./xampp/apache/bin'); - -$file->copyFile('./xampp/apache/binold/htpasswd.exe', './xampp/apache/bin/htpasswd.exe'); -$file->copyFile('./xampp/apache/binold/httpd.exe', './xampp/apache/bin/httpd.exe'); -$file->copyFile('./xampp/apache/binold/libapr-1.dll', './xampp/apache/bin/libapr-1.dll'); -$file->copyFile('./xampp/apache/binold/libapriconv-1.dll', './xampp/apache/bin/libapriconv-1.dll'); -$file->copyFile('./xampp/apache/binold/libaprutil-1.dll', './xampp/apache/bin/libaprutil-1.dll'); -$file->copyFile('./xampp/apache/binold/libhttpd.dll', './xampp/apache/bin/libhttpd.dll'); -$file->copyFile('./xampp/apache/binold/zlib1.dll', './xampp/apache/bin/zlib1.dll'); -$file->copyFile('./xampp/apache/binold/pv.exe', './xampp/apache/bin/pv.exe'); -$file->removeDir('./xampp/apache/binold'); - -/* Process the apache's config file. */ -$httpdConf = file_get_contents('./xampp/apache/conf/httpd.conf'); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule asis_module modules/mod_asis.so', '#LoadModule asis_module modules/mod_asis.so', $httpdConf); -$httpdConf = str_replace('LoadModule auth_digest_module modules/mod_auth_digest.so', '#LoadModule auth_digest_module modules/mod_auth_digest.so', $httpdConf); -$httpdConf = str_replace('LoadModule authn_default_module modules/mod_authn_default.so', '#LoadModule authn_default_module modules/mod_authn_default.so', $httpdConf); -$httpdConf = str_replace('LoadModule authn_file_module modules/mod_authn_file.so', '#LoadModule authn_file_module modules/mod_authn_file.so', $httpdConf); -$httpdConf = str_replace('LoadModule authz_default_module modules/mod_authz_default.so', '#LoadModule authz_default_module modules/mod_authz_default.so', $httpdConf); - -$httpdConf = file_get_contents('./xampp/apache/conf/httpd.conf'); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); -$httpdConf = str_replace('LoadModule asis_module modules/mod_asis.so', '#LoadModule asis_module modules/mod_asis.so', $httpdConf); -$httpdConf = str_replace('LoadModule auth_digest_module modules/mod_auth_digest.so', '#LoadModule auth_digest_module modules/mod_auth_digest.so', $httpdConf); -$httpdConf = str_replace('LoadModule authn_default_module modules/mod_authn_default.so', '#LoadModule authn_default_module modules/mod_authn_default.so', $httpdConf); -$httpdConf = str_replace('LoadModule authn_file_module modules/mod_authn_file.so', '#LoadModule authn_file_module modules/mod_authn_file.so', $httpdConf); -$httpdConf = str_replace('LoadModule authz_default_module modules/mod_authz_default.so', '#LoadModule authz_default_module modules/mod_authz_default.so', $httpdConf); -$httpdConf = str_replace('LoadModule authz_groupfile_module modules/mod_authz_groupfile.so','#LoadModule authz_groupfile_module modules/mod_authz_groupfile.so', $httpdConf); -$httpdConf = str_replace('LoadModule cgi_module modules/mod_cgi.so', '#LoadModule cgi_module modules/mod_cgi.so', $httpdConf); -$httpdConf = str_replace('LoadModule dav_lock_module modules/mod_dav_lock.so', '#LoadModule dav_lock_module modules/mod_dav_lock.so', $httpdConf); -$httpdConf = str_replace('LoadModule headers_module modules/mod_headers.so', '#LoadModule headers_module modules/mod_headers.so', $httpdConf); -$httpdConf = str_replace('LoadModule include_module modules/mod_include.so', '#LoadModule include_module modules/mod_include.so', $httpdConf); -$httpdConf = str_replace('LoadModule info_module modules/mod_info.so', '#LoadModule info_module modules/mod_info.so', $httpdConf); -$httpdConf = str_replace('LoadModule isapi_module modules/mod_isapi.so', '#LoadModule isapi_module modules/mod_isapi.so', $httpdConf); -$httpdConf = str_replace('LoadModule log_config_module modules/mod_log_config.so', '#LoadModule log_config_module modules/mod_log_config.so', $httpdConf); -$httpdConf = str_replace('LoadModule negotiation_module modules/mod_negotiation.so', '#LoadModule negotiation_module modules/mod_negotiation.so', $httpdConf); -$httpdConf = str_replace('LoadModule proxy_module modules/mod_proxy.so', '#LoadModule proxy_module modules/mod_proxy.so', $httpdConf); -$httpdConf = str_replace('LoadModule proxy_ajp_module modules/mod_proxy_ajp.so', '#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so', $httpdConf); -$httpdConf = str_replace('LoadModule ssl_module modules/mod_ssl.so', '#LoadModule ssl_module modules/mod_ssl.so', $httpdConf); -$httpdConf = str_replace('LoadModule status_module modules/mod_status.so', '#LoadModule status_module modules/mod_status.so', $httpdConf); -$httpdConf = str_replace('#LoadModule deflate_module modules/mod_deflate.so', 'LoadModule deflate_module modules/mod_deflate.so', $httpdConf); - -$httpdConf = str_replace('Include "conf/extra/httpd-perl.conf"', '#Include "conf/extra/httpd-perl.conf"', $httpdConf); -$httpdConf = str_replace('Include "conf/extra/httpd-multilang-errordoc.conf"', '#Include "conf/extra/httpd-multilang-errordoc.conf"', $httpdConf); -$httpdConf = str_replace('Include "conf/extra/httpd-userdir.conf"', '#Include "conf/extra/httpd-userdir.conf"', $httpdConf); -$httpdConf = str_replace('Include "conf/extra/httpd-info.conf"', '#Include "conf/extra/httpd-info.conf"', $httpdConf); -$httpdConf = str_replace('Include "conf/extra/httpd-proxy.conf"', '#Include "conf/extra/httpd-proxy.conf"', $httpdConf); -$httpdConf = str_replace('Include "conf/extra/httpd-ssl.conf"', '#Include "conf/extra/httpd-ssl.conf"', $httpdConf); - -$httpdConf = explode("\n", $httpdConf); -foreach($httpdConf as $key => $line) -{ - $line = trim($line); - if(empty($line) or substr($line, 0, 1) == '#') unset($httpdConf[$key]); -} -$httpdConf = join("\n", $httpdConf); -file_put_contents('./xampp/apache/conf/httpd.conf', str_replace('88', '80', $httpdConf)); -file_put_contents('./xampp/apache/conf/httpd80.conf', str_replace('88', '80', $httpdConf)); -file_put_contents('./xampp/apache/conf/httpd88.conf', str_replace('80', '88', $httpdConf)); - -/* Remove useless config files. */ -$file->removeDir('./xampp/apache/conf/ssl.crl'); -$file->removeDir('./xampp/apache/conf/ssl.crt'); -$file->removeDir('./xampp/apache/conf/ssl.csr'); -$file->removeDir('./xampp/apache/conf/ssl.key'); -$file->removeFile('./xampp/apache/conf/extra/httpd-ajp.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-proxy.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-perl.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-dav.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-info.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-multilang-errordoc.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-ssl.conf'); -$file->removeFile('./xampp/apache/conf/extra/httpd-userdir.conf'); - -/* Empty the htdocs directory. */ -$file->removeDir('./xampp/htdocs'); -$file->mkdir('./xampp/htdocs'); - -/* Process mysql. */ -$file->removeDir('./xampp/mysql/backup'); -$file->removeDir('./xampp/mysql/include'); -$file->removeDir('./xampp/mysql/lib'); -$file->removeDir('./xampp/mysql/scripts'); -$file->removeDir('./xampp/mysql/sql-bench'); - -/* Process mysql's bin directory. */ -$file->rename('./xampp/mysql/bin', './xampp/mysql/binold'); -$file->mkdir('./xampp/mysql/bin'); - -$file->copyFile('./xampp/mysql/binold/mysql.exe', './xampp/mysql/bin/mysql.exe'); -$file->copyFile('./xampp/mysql/binold/mysqld.exe', './xampp/mysql/bin/mysqld.exe'); -$file->copyFile('./xampp/mysql/binold/mysqldump.exe', './xampp/mysql/bin/mysqldump.exe'); -$file->copyFile('./xampp/mysql/binold/my.ini', './xampp/mysql/bin/my.ini'); - -$file->removeDir('./xampp/mysql/binold'); - -/* Process mysql's share diectory. */ -$file->rename('./xampp/mysql/share', './xampp/mysql/shareold'); -$file->mkdir('./xampp/mysql/share'); -$file->mkdir('./xampp/mysql/share/english'); -$file->copyFile('./xampp/mysql/shareold/english/errmsg.sys', './xampp/mysql/share/english/errmsg.sys'); -$file->removeDir('../xampp/mysql/shareold'); - -/* Process mysql's data directory. */ -$file->removeDir('./xampp/mysql/data/phpmyadmin'); -$file->removeDir('./xampp/mysql/data/test'); -$file->removeDir('./xampp/mysql/data/webauth'); -$file->removeDir('./xampp/mysql/data/cdcol'); -$file->batchRemoveFile('./xampp/mysql/data/ib*'); -$file->batchRemoveFile('./xampp/mysql/data/mysql*'); - -/* Remove mysql's useless config files. */ -$file->batchRemoveFile('./xampp/mysql/*.ini'); -$file->removeFile('./xampp/mysql/README'); -$file->removeFile('./xampp/mysql/COPYING'); - -/* Process mysql's conf file. */ -$myConf = file_get_contents('./xampp/mysql/bin/my.ini'); -$myConf = str_replace('#bind-address="127.0.0.1"', 'bind-address="127.0.0.1"', $myConf); -$myConf = explode("\n", $myConf); -foreach($myConf as $key => $line) -{ - $line = trim($line); - if(empty($line) or substr($line, 0, 1) == '#') unset($myConf[$key]); -} -$myConf = join("\n", $myConf); -file_put_contents('./xampp/mysql/bin/my.ini', str_replace('3308', '3306', $myConf)); -file_put_contents('./xampp/mysql/bin/my3306.ini', str_replace('3308', '3306', $myConf)); -file_put_contents('./xampp/mysql/bin/my3308.ini', str_replace('3306', '3308', $myConf)); - -/* Processing php. */ -$file->removeDir('./xampp/php/cfg'); -$file->removeDir('./xampp/php/data'); -$file->removeDir('./xampp/php/DB'); -$file->removeDir('./xampp/php/dev'); -$file->removeDir('./xampp/php/docs'); -$file->removeDir('./xampp/php/PEAR'); -$file->removeDir('./xampp/php/tests'); -$file->removeDir('./xampp/php/Text'); -$file->removeDir('./xampp/php/tmp'); -$file->removeDir('./xampp/php/www'); -$file->batchRemoveFile('./xampp/php/dbunit*'); -$file->batchRemoveFile('./xampp/php/*.bat'); -$file->batchRemoveFile('./xampp/php/*.txt'); -$file->batchRemoveFile('./xampp/php/php.ini-*'); -$file->batchRemoveFile('./xampp/php/*.reg'); -$file->batchRemoveFile('./xampp/php/pci*'); -$file->batchRemoveFile('./xampp/php/*.phar'); -$file->batchRemoveFile('./xampp/php/php-*.exe'); -$file->batchRemoveFile('./xampp/php/phpcov'); -$file->batchRemoveFile('./xampp/php/phptok'); -$file->batchRemoveFile('./xampp/php/phpunit'); -$file->batchRemoveFile('./xampp/php/*.php'); - -$file->rename('./xampp/php/php5apache2_2.dll', './xampp/php/php5apache2_2.bak'); -$file->rename('./xampp/php/php5ts.dll', './xampp/php/php5ts.bak'); -$file->batchRemoveFile('./xampp/php/*.dll'); -$file->rename('./xampp/php/php5apache2_2.bak', './xampp/php/php5apache2_2.dll'); -$file->rename('./xampp/php/php5ts.bak', './xampp/php/php5ts.dll'); - -/* Process php ini file. */ -$phpConfig = file_get_contents('./xampp/php/php.ini'); -$phpConfig = str_replace('extension=php_curl.dll',';extension=php_curl.dll', $phpConfig); -$phpConfig = str_replace('extension=php_exif.dll',';extension=php_exif.dll', $phpConfig); -$phpConfig = str_replace('extension=php_gettext.dll',';extension=php_gettext.dll', $phpConfig); -$phpConfig = str_replace('extension=php_pdo_odbc.dll',';extension=php_pdo_odbc.dll', $phpConfig); -$phpConfig = str_replace('extension=php_pdo_sqlite.dll',';extension=php_pdo_sqlite.dll', $phpConfig); -$phpConfig = str_replace('extension=php_soap.dll',';extension=php_soap.dll', $phpConfig); -$phpConfig = str_replace('extension=php_sqlite.dll',';extension=php_sqlite.dll', $phpConfig); -$phpConfig = str_replace('extension=php_sqlite3.dll',';extension=php_sqlite3.dll', $phpConfig); -$phpConfig = str_replace('extension=php_xmlrpc.dll',';extension=php_xmlrpc.dll', $phpConfig); - -/* Remove empty and comment lines. */ -$phpConfig = explode("\n", $phpConfig); -foreach($phpConfig as $key => $line) -{ - $line = trim($line); - if(empty($line)) unset($phpConfig[$key]); - if(substr($line, 0, 1) == ';') unset($phpConfig[$key]); -} -$phpConfig = join("\n", $phpConfig); - -file_put_contents('./xampp/php/php.ini', $phpConfig); - -/* Process php's ext directory. */ -$file->rename('./xampp/php/ext', './xampp/php/extold'); -$file->mkdir('./xampp/php/ext'); -$file->copyFile('./xampp/php/extold/php_bz2.dll', './xampp/php/ext/php_bz2.dll'); -$file->copyFile('./xampp/php/extold/php_eaccelerator_ts.dll', './xampp/php/ext/php_eaccelerator_ts.dll'); -$file->copyFile('./xampp/php/extold/php_gd2.dll', './xampp/php/ext/php_gd2.dll'); -$file->copyFile('./xampp/php/extold/php_imap.dll', './xampp/php/ext/php_imap.dll'); -$file->copyFile('./xampp/php/extold/php_mbstring.dll', './xampp/php/ext/php_mbstring.dll'); -$file->copyFile('./xampp/php/extold/php_mysql.dll', './xampp/php/ext/php_mysql.dll'); -$file->copyFile('./xampp/php/extold/php_mysqli.dll', './xampp/php/ext/php_mysqli.dll'); -$file->copyFile('./xampp/php/extold/php_pdo_mysql.dll', './xampp/php/ext/php_pdo_mysql.dll'); -$file->copyFile('./xampp/php/extold/php_sockets.dll', './xampp/php/ext/php_sockets.dll'); -$file->removeDir('./xampp/php/extold'); - -/* Process sqlbuddy. */ -if(!is_dir('./xampp/admin/')) $file->mkdir('./xampp/admin/'); -if(!is_dir('./xampp/admin/sqlbuddy')) -{ - echo `$sevenz x -y $sqlbuddy`; - $file->rename('./sqlbuddy', './xampp/admin/sqlbuddy'); -} - -/* Process control panel. */ -if(file_exists('./xampp/xampp-control.exe')) $file->rename('./xampp/xampp-control.exe', './xampp/zentaoamp-control-en.exe'); -$file->copyFile($buildDir . '/zentaoamp.exe', './xampp/zentaoamp-control-cn.exe'); -$file->batchRemoveFile('./xampp/xampp_s*'); - -/* Copy index.php. */ -$file->copyFile($buildDir . '/index.php', './xampp/htdocs/index.php'); - -/* Copy zentao.conf. */ -$file->copyFile($buildDir . '/zentao.conf', './xampp/apache/conf/extra/httpd-xampp.conf'); +removeDir('./xampp/anonymous'); +$file->removeDir('./xampp/cgi-bin'); +$file->removeDir('./xampp/contrib'); +$file->removeDir('./xampp/contrib'); +$file->removeDir('./xampp/install'); +$file->removeDir('./xampp/licenses'); +$file->removeDir('./xampp/nsi'); +$file->removeDir('./xampp/perl'); +$file->removeDir('./xampp/phpmyadmin'); +$file->removeDir('./xampp/sendmail'); +$file->removeDir('./xampp/security'); +$file->removeDir('./xampp/src'); +$file->batchRemoveFile('./xampp/tmp/*'); +$file->removeDir('./xampp/webdav'); +$file->removeDir('./xampp/setup_xampp.bat'); +$file->batchRemoveFile('./xampp/*.txt'); + +/* Process apache module. */ +$file->batchRemoveFile('./xampp/apache/*.txt'); +$file->batchRemoveFile('./xampp/apache/*.bat'); +$file->rename('./xampp/apache/modules', './xampp/apache/modulesold'); +$file->mkdir('./xampp/apache/modules'); + +$file->copyFile('./xampp/apache/modulesold/mod_auth_basic.so', './xampp/apache/modules/mod_auth_basic.so'); +$file->copyFile('./xampp/apache/modulesold/mod_mime_magic.so', './xampp/apache/modules/mod_mime_magic.so'); +$file->copyFile('./xampp/apache/modulesold/mod_mime.so', './xampp/apache/modules/mod_mime.so'); +$file->copyFile('./xampp/apache/modulesold/mod_expires.so', './xampp/apache/modules/mod_expires.so'); +$file->copyFile('./xampp/apache/modulesold/mod_env.so', './xampp/apache/modules/mod_env.so'); +$file->copyFile('./xampp/apache/modulesold/mod_rewrite.so', './xampp/apache/modules/mod_rewrite.so'); +$file->copyFile('./xampp/apache/modulesold/mod_vhost_alias.so','./xampp/apache/modules/mod_vhost_alias.so'); +$file->copyFile('./xampp/apache/modulesold/mod_setenvif.so', './xampp/apache/modules/mod_setenvif.so'); +$file->copyFile('./xampp/apache/modulesold/mod_autoindex.so', './xampp/apache/modules/mod_autoindex.so'); +$file->copyFile('./xampp/apache/modulesold/mod_authz_user.so', './xampp/apache/modules/mod_authz_user.so'); +$file->copyFile('./xampp/apache/modulesold/mod_authz_host.so', './xampp/apache/modules/mod_authz_host.so'); +$file->copyFile('./xampp/apache/modulesold/mod_alias.so', './xampp/apache/modules/mod_alias.so'); +$file->copyFile('./xampp/apache/modulesold/mod_dir.so', './xampp/apache/modules/mod_dir.so'); +$file->copyFile('./xampp/apache/modulesold/mod_deflate.so', './xampp/apache/modules/mod_deflate.so'); +$file->removeDir('./xampp/apache/modulesold'); + +/* Remove apache's error, icons, include, lib, logs directory. */ +$file->removeDir('./xampp/apache/error'); +$file->removeDir('./xampp/apache/icons'); +$file->removeDir('./xampp/apache/include'); +$file->removeDir('./xampp/apache/lib'); +$file->batchRemoveFile('./xampp/apache/logs/*.log'); + +$file->rename('./xampp/apache/bin', './xampp/apache/binold'); +$file->mkdir('./xampp/apache/bin'); + +$file->copyFile('./xampp/apache/binold/htpasswd.exe', './xampp/apache/bin/htpasswd.exe'); +$file->copyFile('./xampp/apache/binold/httpd.exe', './xampp/apache/bin/httpd.exe'); +$file->copyFile('./xampp/apache/binold/libapr-1.dll', './xampp/apache/bin/libapr-1.dll'); +$file->copyFile('./xampp/apache/binold/libapriconv-1.dll', './xampp/apache/bin/libapriconv-1.dll'); +$file->copyFile('./xampp/apache/binold/libaprutil-1.dll', './xampp/apache/bin/libaprutil-1.dll'); +$file->copyFile('./xampp/apache/binold/libhttpd.dll', './xampp/apache/bin/libhttpd.dll'); +$file->copyFile('./xampp/apache/binold/zlib1.dll', './xampp/apache/bin/zlib1.dll'); +$file->copyFile('./xampp/apache/binold/pv.exe', './xampp/apache/bin/pv.exe'); +$file->removeDir('./xampp/apache/binold'); + +/* Process the apache's config file. */ +$httpdConf = file_get_contents('./xampp/apache/conf/httpd.conf'); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule asis_module modules/mod_asis.so', '#LoadModule asis_module modules/mod_asis.so', $httpdConf); +$httpdConf = str_replace('LoadModule auth_digest_module modules/mod_auth_digest.so', '#LoadModule auth_digest_module modules/mod_auth_digest.so', $httpdConf); +$httpdConf = str_replace('LoadModule authn_default_module modules/mod_authn_default.so', '#LoadModule authn_default_module modules/mod_authn_default.so', $httpdConf); +$httpdConf = str_replace('LoadModule authn_file_module modules/mod_authn_file.so', '#LoadModule authn_file_module modules/mod_authn_file.so', $httpdConf); +$httpdConf = str_replace('LoadModule authz_default_module modules/mod_authz_default.so', '#LoadModule authz_default_module modules/mod_authz_default.so', $httpdConf); + +$httpdConf = file_get_contents('./xampp/apache/conf/httpd.conf'); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule actions_module modules/mod_actions.so', '#LoadModule actions_module modules/mod_actions.so', $httpdConf); +$httpdConf = str_replace('LoadModule asis_module modules/mod_asis.so', '#LoadModule asis_module modules/mod_asis.so', $httpdConf); +$httpdConf = str_replace('LoadModule auth_digest_module modules/mod_auth_digest.so', '#LoadModule auth_digest_module modules/mod_auth_digest.so', $httpdConf); +$httpdConf = str_replace('LoadModule authn_default_module modules/mod_authn_default.so', '#LoadModule authn_default_module modules/mod_authn_default.so', $httpdConf); +$httpdConf = str_replace('LoadModule authn_file_module modules/mod_authn_file.so', '#LoadModule authn_file_module modules/mod_authn_file.so', $httpdConf); +$httpdConf = str_replace('LoadModule authz_default_module modules/mod_authz_default.so', '#LoadModule authz_default_module modules/mod_authz_default.so', $httpdConf); +$httpdConf = str_replace('LoadModule authz_groupfile_module modules/mod_authz_groupfile.so','#LoadModule authz_groupfile_module modules/mod_authz_groupfile.so', $httpdConf); +$httpdConf = str_replace('LoadModule cgi_module modules/mod_cgi.so', '#LoadModule cgi_module modules/mod_cgi.so', $httpdConf); +$httpdConf = str_replace('LoadModule dav_lock_module modules/mod_dav_lock.so', '#LoadModule dav_lock_module modules/mod_dav_lock.so', $httpdConf); +$httpdConf = str_replace('LoadModule headers_module modules/mod_headers.so', '#LoadModule headers_module modules/mod_headers.so', $httpdConf); +$httpdConf = str_replace('LoadModule include_module modules/mod_include.so', '#LoadModule include_module modules/mod_include.so', $httpdConf); +$httpdConf = str_replace('LoadModule info_module modules/mod_info.so', '#LoadModule info_module modules/mod_info.so', $httpdConf); +$httpdConf = str_replace('LoadModule isapi_module modules/mod_isapi.so', '#LoadModule isapi_module modules/mod_isapi.so', $httpdConf); +$httpdConf = str_replace('LoadModule log_config_module modules/mod_log_config.so', '#LoadModule log_config_module modules/mod_log_config.so', $httpdConf); +$httpdConf = str_replace('LoadModule negotiation_module modules/mod_negotiation.so', '#LoadModule negotiation_module modules/mod_negotiation.so', $httpdConf); +$httpdConf = str_replace('LoadModule proxy_module modules/mod_proxy.so', '#LoadModule proxy_module modules/mod_proxy.so', $httpdConf); +$httpdConf = str_replace('LoadModule proxy_ajp_module modules/mod_proxy_ajp.so', '#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so', $httpdConf); +$httpdConf = str_replace('LoadModule ssl_module modules/mod_ssl.so', '#LoadModule ssl_module modules/mod_ssl.so', $httpdConf); +$httpdConf = str_replace('LoadModule status_module modules/mod_status.so', '#LoadModule status_module modules/mod_status.so', $httpdConf); +$httpdConf = str_replace('#LoadModule deflate_module modules/mod_deflate.so', 'LoadModule deflate_module modules/mod_deflate.so', $httpdConf); + +$httpdConf = str_replace('Include "conf/extra/httpd-perl.conf"', '#Include "conf/extra/httpd-perl.conf"', $httpdConf); +$httpdConf = str_replace('Include "conf/extra/httpd-multilang-errordoc.conf"', '#Include "conf/extra/httpd-multilang-errordoc.conf"', $httpdConf); +$httpdConf = str_replace('Include "conf/extra/httpd-userdir.conf"', '#Include "conf/extra/httpd-userdir.conf"', $httpdConf); +$httpdConf = str_replace('Include "conf/extra/httpd-info.conf"', '#Include "conf/extra/httpd-info.conf"', $httpdConf); +$httpdConf = str_replace('Include "conf/extra/httpd-proxy.conf"', '#Include "conf/extra/httpd-proxy.conf"', $httpdConf); +$httpdConf = str_replace('Include "conf/extra/httpd-ssl.conf"', '#Include "conf/extra/httpd-ssl.conf"', $httpdConf); + +$httpdConf = explode("\n", $httpdConf); +foreach($httpdConf as $key => $line) +{ + $line = trim($line); + if(empty($line) or substr($line, 0, 1) == '#') unset($httpdConf[$key]); +} +$httpdConf = join("\n", $httpdConf); +file_put_contents('./xampp/apache/conf/httpd.conf', str_replace('88', '80', $httpdConf)); +file_put_contents('./xampp/apache/conf/httpd80.conf', str_replace('88', '80', $httpdConf)); +file_put_contents('./xampp/apache/conf/httpd88.conf', str_replace('80', '88', $httpdConf)); + +/* Remove useless config files. */ +$file->removeDir('./xampp/apache/conf/ssl.crl'); +$file->removeDir('./xampp/apache/conf/ssl.crt'); +$file->removeDir('./xampp/apache/conf/ssl.csr'); +$file->removeDir('./xampp/apache/conf/ssl.key'); +$file->removeFile('./xampp/apache/conf/extra/httpd-ajp.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-proxy.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-perl.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-dav.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-info.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-multilang-errordoc.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-ssl.conf'); +$file->removeFile('./xampp/apache/conf/extra/httpd-userdir.conf'); + +/* Empty the htdocs directory. */ +$file->removeDir('./xampp/htdocs'); +$file->mkdir('./xampp/htdocs'); + +/* Process mysql. */ +$file->removeDir('./xampp/mysql/backup'); +$file->removeDir('./xampp/mysql/include'); +$file->removeDir('./xampp/mysql/lib'); +$file->removeDir('./xampp/mysql/scripts'); +$file->removeDir('./xampp/mysql/sql-bench'); + +/* Process mysql's bin directory. */ +$file->rename('./xampp/mysql/bin', './xampp/mysql/binold'); +$file->mkdir('./xampp/mysql/bin'); + +$file->copyFile('./xampp/mysql/binold/mysql.exe', './xampp/mysql/bin/mysql.exe'); +$file->copyFile('./xampp/mysql/binold/mysqld.exe', './xampp/mysql/bin/mysqld.exe'); +$file->copyFile('./xampp/mysql/binold/mysqldump.exe', './xampp/mysql/bin/mysqldump.exe'); +$file->copyFile('./xampp/mysql/binold/my.ini', './xampp/mysql/bin/my.ini'); + +$file->removeDir('./xampp/mysql/binold'); + +/* Process mysql's share diectory. */ +$file->rename('./xampp/mysql/share', './xampp/mysql/shareold'); +$file->mkdir('./xampp/mysql/share'); +$file->mkdir('./xampp/mysql/share/english'); +$file->copyFile('./xampp/mysql/shareold/english/errmsg.sys', './xampp/mysql/share/english/errmsg.sys'); +$file->removeDir('../xampp/mysql/shareold'); + +/* Process mysql's data directory. */ +$file->removeDir('./xampp/mysql/data/phpmyadmin'); +$file->removeDir('./xampp/mysql/data/test'); +$file->removeDir('./xampp/mysql/data/webauth'); +$file->removeDir('./xampp/mysql/data/cdcol'); +$file->batchRemoveFile('./xampp/mysql/data/ib*'); +$file->batchRemoveFile('./xampp/mysql/data/mysql*'); + +/* Remove mysql's useless config files. */ +$file->batchRemoveFile('./xampp/mysql/*.ini'); +$file->removeFile('./xampp/mysql/README'); +$file->removeFile('./xampp/mysql/COPYING'); + +/* Process mysql's conf file. */ +$myConf = file_get_contents('./xampp/mysql/bin/my.ini'); +$myConf = str_replace('#bind-address="127.0.0.1"', 'bind-address="127.0.0.1"', $myConf); +$myConf = explode("\n", $myConf); +foreach($myConf as $key => $line) +{ + $line = trim($line); + if(empty($line) or substr($line, 0, 1) == '#') unset($myConf[$key]); +} +$myConf = join("\n", $myConf); +file_put_contents('./xampp/mysql/bin/my.ini', str_replace('3308', '3306', $myConf)); +file_put_contents('./xampp/mysql/bin/my3306.ini', str_replace('3308', '3306', $myConf)); +file_put_contents('./xampp/mysql/bin/my3308.ini', str_replace('3306', '3308', $myConf)); + +/* Processing php. */ +$file->removeDir('./xampp/php/cfg'); +$file->removeDir('./xampp/php/data'); +$file->removeDir('./xampp/php/DB'); +$file->removeDir('./xampp/php/dev'); +$file->removeDir('./xampp/php/docs'); +$file->removeDir('./xampp/php/PEAR'); +$file->removeDir('./xampp/php/tests'); +$file->removeDir('./xampp/php/Text'); +$file->removeDir('./xampp/php/tmp'); +$file->removeDir('./xampp/php/www'); +$file->batchRemoveFile('./xampp/php/dbunit*'); +$file->batchRemoveFile('./xampp/php/*.bat'); +$file->batchRemoveFile('./xampp/php/*.txt'); +$file->batchRemoveFile('./xampp/php/php.ini-*'); +$file->batchRemoveFile('./xampp/php/*.reg'); +$file->batchRemoveFile('./xampp/php/pci*'); +$file->batchRemoveFile('./xampp/php/*.phar'); +$file->batchRemoveFile('./xampp/php/php-*.exe'); +$file->batchRemoveFile('./xampp/php/phpcov'); +$file->batchRemoveFile('./xampp/php/phptok'); +$file->batchRemoveFile('./xampp/php/phpunit'); +$file->batchRemoveFile('./xampp/php/*.php'); + +$file->rename('./xampp/php/php5apache2_2.dll', './xampp/php/php5apache2_2.bak'); +$file->rename('./xampp/php/php5ts.dll', './xampp/php/php5ts.bak'); +$file->batchRemoveFile('./xampp/php/*.dll'); +$file->rename('./xampp/php/php5apache2_2.bak', './xampp/php/php5apache2_2.dll'); +$file->rename('./xampp/php/php5ts.bak', './xampp/php/php5ts.dll'); + +/* Process php ini file. */ +$phpConfig = file_get_contents('./xampp/php/php.ini'); +$phpConfig = str_replace('extension=php_curl.dll',';extension=php_curl.dll', $phpConfig); +$phpConfig = str_replace('extension=php_exif.dll',';extension=php_exif.dll', $phpConfig); +$phpConfig = str_replace('extension=php_gettext.dll',';extension=php_gettext.dll', $phpConfig); +$phpConfig = str_replace('extension=php_pdo_odbc.dll',';extension=php_pdo_odbc.dll', $phpConfig); +$phpConfig = str_replace('extension=php_pdo_sqlite.dll',';extension=php_pdo_sqlite.dll', $phpConfig); +$phpConfig = str_replace('extension=php_soap.dll',';extension=php_soap.dll', $phpConfig); +$phpConfig = str_replace('extension=php_sqlite.dll',';extension=php_sqlite.dll', $phpConfig); +$phpConfig = str_replace('extension=php_sqlite3.dll',';extension=php_sqlite3.dll', $phpConfig); +$phpConfig = str_replace('extension=php_xmlrpc.dll',';extension=php_xmlrpc.dll', $phpConfig); + +/* Remove empty and comment lines. */ +$phpConfig = explode("\n", $phpConfig); +foreach($phpConfig as $key => $line) +{ + $line = trim($line); + if(empty($line)) unset($phpConfig[$key]); + if(substr($line, 0, 1) == ';') unset($phpConfig[$key]); +} +$phpConfig = join("\n", $phpConfig); + +file_put_contents('./xampp/php/php.ini', $phpConfig); + +/* Process php's ext directory. */ +$file->rename('./xampp/php/ext', './xampp/php/extold'); +$file->mkdir('./xampp/php/ext'); +$file->copyFile('./xampp/php/extold/php_bz2.dll', './xampp/php/ext/php_bz2.dll'); +$file->copyFile('./xampp/php/extold/php_eaccelerator_ts.dll', './xampp/php/ext/php_eaccelerator_ts.dll'); +$file->copyFile('./xampp/php/extold/php_gd2.dll', './xampp/php/ext/php_gd2.dll'); +$file->copyFile('./xampp/php/extold/php_imap.dll', './xampp/php/ext/php_imap.dll'); +$file->copyFile('./xampp/php/extold/php_mbstring.dll', './xampp/php/ext/php_mbstring.dll'); +$file->copyFile('./xampp/php/extold/php_mysql.dll', './xampp/php/ext/php_mysql.dll'); +$file->copyFile('./xampp/php/extold/php_mysqli.dll', './xampp/php/ext/php_mysqli.dll'); +$file->copyFile('./xampp/php/extold/php_pdo_mysql.dll', './xampp/php/ext/php_pdo_mysql.dll'); +$file->copyFile('./xampp/php/extold/php_sockets.dll', './xampp/php/ext/php_sockets.dll'); +$file->removeDir('./xampp/php/extold'); + +/* Process sqlbuddy. */ +if(!is_dir('./xampp/admin/')) $file->mkdir('./xampp/admin/'); +if(!is_dir('./xampp/admin/sqlbuddy')) +{ + echo `$sevenz x -y $sqlbuddy`; + $file->rename('./sqlbuddy', './xampp/admin/sqlbuddy'); +} + +/* Process control panel. */ +if(file_exists('./xampp/xampp-control.exe')) $file->rename('./xampp/xampp-control.exe', './xampp/zentaoamp-control-en.exe'); +$file->copyFile($buildDir . '/zentaoamp.exe', './xampp/zentaoamp-control-cn.exe'); +$file->batchRemoveFile('./xampp/xampp_s*'); + +/* Copy index.php. */ +$file->copyFile($buildDir . '/index.php', './xampp/htdocs/index.php'); + +/* Copy zentao.conf. */ +$file->copyFile($buildDir . '/zentao.conf', './xampp/apache/conf/extra/httpd-xampp.conf'); diff --git a/build/windows/xampp/index.php b/build/windows/xampp/index.php index d6e3fef25b..b7d3af7091 100644 --- a/build/windows/xampp/index.php +++ b/build/windows/xampp/index.php @@ -1,22 +1,22 @@ - - - - - - 欢迎使用禅道集成运行环境! - - -

欢迎使用禅道集成运行环境!

-

关于该环境

-该集成环境基于xampp usb lite版本精简而成,同时内置了禅道的应用程序。 -xampp是非常优秀的apache, mysql, php集成运行环境,官方网站是:http://www.apachefriends.org/zh_cn/xampp.html - -

常用链接

- - -

访问禅道

- - + + + + + + 欢迎使用禅道集成运行环境! + + +

欢迎使用禅道集成运行环境!

+

关于该环境

+该集成环境基于xampp usb lite版本精简而成,同时内置了禅道的应用程序。 +xampp是非常优秀的apache, mysql, php集成运行环境,官方网站是:http://www.apachefriends.org/zh_cn/xampp.html + +

常用链接

+ + +

访问禅道

+ + diff --git a/config/config.php b/config/config.php index 7850c75910..6f52c2a120 100644 --- a/config/config.php +++ b/config/config.php @@ -1,121 +1,121 @@ - - * @package config - * @version $Id$ - * @link http://www.zentao.net - */ -/* Basic settings. */ -$config->version = '3.0.beta2'; // The version of zentaopms. Don't change it. -$config->encoding = 'UTF-8'; // The encoding of znetaopms. -$config->cookieLife = time() + 2592000; // The cookie life time. -$config->timezone = 'Asia/Shanghai'; // The time zone setting, for more see http://www.php.net/manual/en/timezones.php -$config->webRoot = ''; // The root path of the pms. - -/* The request settings. */ -$config->requestType = 'PATH_INFO'; // The request type: PATH_INFO|GET, if PATH_INFO, must use url rewrite. -$config->pathType = 'clean'; // If the request type is PATH_INFO, the path type. -$config->requestFix = '-'; // The divider in the url when PATH_INFO. -$config->moduleVar = 'm'; // requestType=GET: the module var name. -$config->methodVar = 'f'; // requestType=GET: the method var name. -$config->viewVar = 't'; // requestType=GET: the view var name. -$config->sessionVar = 'sid'; // requestType=GET: the session var name. - -/* Supported views. */ -$config->views = ',html,json,'; - -/* Set the wide window size. */ -$config->wideSize = 1400; - -/* Supported languages. */ -$config->langs['zh-cn'] = '中文简体'; -$config->langs['zh-tw'] = '中文繁體'; -$config->langs['en'] = 'English'; - -/* Default settings. */ -$config->default->view = 'html'; // Default view. -$config->default->lang = 'en'; // Default language. -$config->default->theme = 'default'; // Default theme. -$config->default->module = 'index'; // Default module. -$config->default->method = 'index'; // Default method. - -/* Upload settings. */ -$config->file->dangers = 'php,jsp,py,rb,asp,'; // Dangerous files. -$config->file->maxSize = 1024 * 1024; // Max size. - -/* Master database settings. */ -$config->db->persistant = false; // Pconnect or not. -$config->db->driver = 'mysql'; // Must be MySQL. Don't support other database server yet. -$config->db->encoding = 'UTF8'; // Encoding of database. -$config->db->strictMode = false; // Turn off the strict mode of MySQL. -//$config->db->emulatePrepare = true; // PDO::ATTR_EMULATE_PREPARES -//$config->db->bufferQuery = true; // PDO::MYSQL_ATTR_USE_BUFFERED_QUERY - -/* Slave database settings. */ -$config->slaveDB->persistant = false; -$config->slaveDB->driver = 'mysql'; -$config->slaveDB->encoding = 'UTF8'; -$config->slaveDB->strictMode = false; -$config->slaveDB->checkCentOS= true; - -/* Include the custom config file. */ -$configRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR; -$myConfig = $configRoot . 'my.php'; -if(file_exists($myConfig)) include $myConfig; - -/* Include extension config files. */ -$extConfigFiles = glob($configRoot . 'ext/*.php'); -foreach($extConfigFiles as $extConfigFile) include $extConfigFile; - -/* Set default table prefix. */ -if(!isset($config->db->prefix)) $config->db->prefix = 'zt_'; - -/* Define the tables. */ -define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`'); -define('TABLE_DEPT', '`' . $config->db->prefix . 'dept`'); -define('TABLE_CONFIG', '`' . $config->db->prefix . 'config`'); -define('TABLE_USER', '`' . $config->db->prefix . 'user`'); -define('TABLE_TODO', '`' . $config->db->prefix . 'todo`'); -define('TABLE_GROUP', '`' . $config->db->prefix . 'group`'); -define('TABLE_GROUPPRIV', '`' . $config->db->prefix . 'groupPriv`'); -define('TABLE_USERGROUP', '`' . $config->db->prefix . 'userGroup`'); -define('TABLE_USERQUERY', '`' . $config->db->prefix . 'userQuery`'); - -define('TABLE_BUG', '`' . $config->db->prefix . 'bug`'); -define('TABLE_CASE', '`' . $config->db->prefix . 'case`'); -define('TABLE_CASESTEP', '`' . $config->db->prefix . 'caseStep`'); -define('TABLE_TESTTASK', '`' . $config->db->prefix . 'testTask`'); -define('TABLE_TESTRUN', '`' . $config->db->prefix . 'testRun`'); -define('TABLE_TESTRESULT', '`' . $config->db->prefix . 'testResult`'); -define('TABLE_USERTPL', '`' . $config->db->prefix . 'userTPL`'); - -define('TABLE_PRODUCT', '`' . $config->db->prefix . 'product`'); -define('TABLE_STORY', '`' . $config->db->prefix . 'story`'); -define('TABLE_STORYSPEC', '`' . $config->db->prefix . 'storySpec`'); -define('TABLE_PRODUCTPLAN', '`' . $config->db->prefix . 'productPlan`'); -define('TABLE_RELEASE', '`' . $config->db->prefix . 'release`'); - -define('TABLE_PROJECT', '`' . $config->db->prefix . 'project`'); -define('TABLE_TASK', '`' . $config->db->prefix . 'task`'); -define('TABLE_TEAM', '`' . $config->db->prefix . 'team`'); -define('TABLE_PROJECTPRODUCT','`' . $config->db->prefix . 'projectProduct`'); -define('TABLE_PROJECTSTORY', '`' . $config->db->prefix . 'projectStory`'); -define('TABLE_TASKESTIMATE', '`' . $config->db->prefix . 'taskEstimate`'); -define('TABLE_EFFORT', '`' . $config->db->prefix . 'effort`'); -define('TABLE_BURN', '`' . $config->db->prefix . 'burn`'); -define('TABLE_BUILD', '`' . $config->db->prefix . 'build`'); - -define('TABLE_DOCLIB', '`' . $config->db->prefix . 'docLib`'); -define('TABLE_DOC', '`' . $config->db->prefix . 'doc`'); - -define('TABLE_MODULE', '`' . $config->db->prefix . 'module`'); -define('TABLE_ACTION', '`' . $config->db->prefix . 'action`'); -define('TABLE_FILE', '`' . $config->db->prefix . 'file`'); -define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`'); -define('TABLE_EXTENSION', '`' . $config->db->prefix . 'extension`'); + + * @package config + * @version $Id$ + * @link http://www.zentao.net + */ +/* Basic settings. */ +$config->version = '3.0.beta2'; // The version of zentaopms. Don't change it. +$config->encoding = 'UTF-8'; // The encoding of znetaopms. +$config->cookieLife = time() + 2592000; // The cookie life time. +$config->timezone = 'Asia/Shanghai'; // The time zone setting, for more see http://www.php.net/manual/en/timezones.php +$config->webRoot = ''; // The root path of the pms. + +/* The request settings. */ +$config->requestType = 'PATH_INFO'; // The request type: PATH_INFO|GET, if PATH_INFO, must use url rewrite. +$config->pathType = 'clean'; // If the request type is PATH_INFO, the path type. +$config->requestFix = '-'; // The divider in the url when PATH_INFO. +$config->moduleVar = 'm'; // requestType=GET: the module var name. +$config->methodVar = 'f'; // requestType=GET: the method var name. +$config->viewVar = 't'; // requestType=GET: the view var name. +$config->sessionVar = 'sid'; // requestType=GET: the session var name. + +/* Supported views. */ +$config->views = ',html,json,'; + +/* Set the wide window size. */ +$config->wideSize = 1400; + +/* Supported languages. */ +$config->langs['zh-cn'] = '中文简体'; +$config->langs['zh-tw'] = '中文繁體'; +$config->langs['en'] = 'English'; + +/* Default settings. */ +$config->default->view = 'html'; // Default view. +$config->default->lang = 'en'; // Default language. +$config->default->theme = 'default'; // Default theme. +$config->default->module = 'index'; // Default module. +$config->default->method = 'index'; // Default method. + +/* Upload settings. */ +$config->file->dangers = 'php,jsp,py,rb,asp,'; // Dangerous files. +$config->file->maxSize = 1024 * 1024; // Max size. + +/* Master database settings. */ +$config->db->persistant = false; // Pconnect or not. +$config->db->driver = 'mysql'; // Must be MySQL. Don't support other database server yet. +$config->db->encoding = 'UTF8'; // Encoding of database. +$config->db->strictMode = false; // Turn off the strict mode of MySQL. +//$config->db->emulatePrepare = true; // PDO::ATTR_EMULATE_PREPARES +//$config->db->bufferQuery = true; // PDO::MYSQL_ATTR_USE_BUFFERED_QUERY + +/* Slave database settings. */ +$config->slaveDB->persistant = false; +$config->slaveDB->driver = 'mysql'; +$config->slaveDB->encoding = 'UTF8'; +$config->slaveDB->strictMode = false; +$config->slaveDB->checkCentOS= true; + +/* Include the custom config file. */ +$configRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR; +$myConfig = $configRoot . 'my.php'; +if(file_exists($myConfig)) include $myConfig; + +/* Include extension config files. */ +$extConfigFiles = glob($configRoot . 'ext/*.php'); +foreach($extConfigFiles as $extConfigFile) include $extConfigFile; + +/* Set default table prefix. */ +if(!isset($config->db->prefix)) $config->db->prefix = 'zt_'; + +/* Define the tables. */ +define('TABLE_COMPANY', '`' . $config->db->prefix . 'company`'); +define('TABLE_DEPT', '`' . $config->db->prefix . 'dept`'); +define('TABLE_CONFIG', '`' . $config->db->prefix . 'config`'); +define('TABLE_USER', '`' . $config->db->prefix . 'user`'); +define('TABLE_TODO', '`' . $config->db->prefix . 'todo`'); +define('TABLE_GROUP', '`' . $config->db->prefix . 'group`'); +define('TABLE_GROUPPRIV', '`' . $config->db->prefix . 'groupPriv`'); +define('TABLE_USERGROUP', '`' . $config->db->prefix . 'userGroup`'); +define('TABLE_USERQUERY', '`' . $config->db->prefix . 'userQuery`'); + +define('TABLE_BUG', '`' . $config->db->prefix . 'bug`'); +define('TABLE_CASE', '`' . $config->db->prefix . 'case`'); +define('TABLE_CASESTEP', '`' . $config->db->prefix . 'caseStep`'); +define('TABLE_TESTTASK', '`' . $config->db->prefix . 'testTask`'); +define('TABLE_TESTRUN', '`' . $config->db->prefix . 'testRun`'); +define('TABLE_TESTRESULT', '`' . $config->db->prefix . 'testResult`'); +define('TABLE_USERTPL', '`' . $config->db->prefix . 'userTPL`'); + +define('TABLE_PRODUCT', '`' . $config->db->prefix . 'product`'); +define('TABLE_STORY', '`' . $config->db->prefix . 'story`'); +define('TABLE_STORYSPEC', '`' . $config->db->prefix . 'storySpec`'); +define('TABLE_PRODUCTPLAN', '`' . $config->db->prefix . 'productPlan`'); +define('TABLE_RELEASE', '`' . $config->db->prefix . 'release`'); + +define('TABLE_PROJECT', '`' . $config->db->prefix . 'project`'); +define('TABLE_TASK', '`' . $config->db->prefix . 'task`'); +define('TABLE_TEAM', '`' . $config->db->prefix . 'team`'); +define('TABLE_PROJECTPRODUCT','`' . $config->db->prefix . 'projectProduct`'); +define('TABLE_PROJECTSTORY', '`' . $config->db->prefix . 'projectStory`'); +define('TABLE_TASKESTIMATE', '`' . $config->db->prefix . 'taskEstimate`'); +define('TABLE_EFFORT', '`' . $config->db->prefix . 'effort`'); +define('TABLE_BURN', '`' . $config->db->prefix . 'burn`'); +define('TABLE_BUILD', '`' . $config->db->prefix . 'build`'); + +define('TABLE_DOCLIB', '`' . $config->db->prefix . 'docLib`'); +define('TABLE_DOC', '`' . $config->db->prefix . 'doc`'); + +define('TABLE_MODULE', '`' . $config->db->prefix . 'module`'); +define('TABLE_ACTION', '`' . $config->db->prefix . 'action`'); +define('TABLE_FILE', '`' . $config->db->prefix . 'file`'); +define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`'); +define('TABLE_EXTENSION', '`' . $config->db->prefix . 'extension`'); diff --git a/lib/api/api.class.php b/lib/api/api.class.php index 9c619ed673..ec65209b85 100755 --- a/lib/api/api.class.php +++ b/lib/api/api.class.php @@ -1,1505 +1,1505 @@ - - * @package API - * @version $Id$ - * @link http://www.zentao.net - */ -class ztclient -{ - public $configFile; - public $zentao; - public $agent; - public $session; - - /** - * The construce function. - * - * @param string $zentaoRoot the zentao root url - * @param string $account the login account - * @param string $password the passwod - * @access public - * @return void - */ - public function __construct($zentaoRoot = '', $account = '', $password = '') - { - $this->agent = new snoopy(); - - /* Assign to $this->zentao. */ - $this->zentao->root = rtrim($zentaoRoot, '/') . '/'; - $this->zentao->account = $account; - $this->zentao->password = md5($password); - - /* Load the remote settings. */ - $config = $this->getRemoteConfig(); - foreach($config as $key => $value) $this->zentao->$key = $value; - - $this->startSession(); - $this->login(); - } - - /** - * Get the settings through getconfig api from remote. - * - * @access private - * @return object - */ - private function getRemoteConfig() - { - $url = $this->zentao->root . '/index.php?mode=getconfig'; - $this->agent->fetchText($url); - $config = json_decode($this->agent->results); - return $config; - } - - /** - * Set the session api. - * - * @access private - * @return string the session api url. - */ - private function setSessionAPI() - { - return $this->setControlAPI('api', 'getsessionid'); - } - - /** - * Set the login api. - * - * @access private - * @return string the login api url. - */ - private function setLoginAPI() - { - return $this->setControlAPI('user', 'login'); - } - - /** - * Set the method api. - * - * @param string $module the module name - * @param string $method the methhod name - * @param string $vars the vars to passwd - * @access private - * @return string the control api string. - */ - private function setControlAPI($module, $method, $vars = '') - { - if($this->zentao->requestType == 'GET') - { - $controlAPI = $this->appendSession($this->zentao->root); - $controlAPI .= "&{$this->zentao->moduleVar}=$module&{$this->zentao->methodVar}=$method&{$this->zentao->viewVar}=json$vars"; - } - elseif($this->zentao->requestType == 'PATH_INFO') - { - $controlAPI = $this->zentao->root . $module . $this->zentao->requestFix . $method . $this->zentao->requestFix; - if($vars) - { - $vars = parse_str($vars); - foreach($vars as $var) $controlAPI .= $var . $this->zentao->requestFix; - } - $controlAPI = rtrim($controlAPI, $this->zentao->requestFix) . '.json'; - $controlAPI = $this->appendSession($controlAPI); - } - return $controlAPI; - } - - /** - * Set the method api. - * - * @param string $module the module name - * @param string $method the methhod name - * @param string $vars the vars to passed - * @access private - * @return string the model api string. - */ - private function setModelAPI($module, $method, $vars = '') - { - $vars = str_replace('&', ',', $vars); - if($this->zentao->requestType == 'GET') - { - $modelAPI = $this->appendSession($this->zentao->root); - $modelAPI .= "&{$this->zentao->moduleVar}=api&{$this->zentao->methodVar}=getModel&{$this->zentao->viewVar}=json"; - $modelAPI .="&module=$module&method=$method¶ms=$vars"; - } - elseif($this->zentao->requestType == 'PATH_INFO') - { - $modelAPI = $this->zentao->root . 'api' . $this->zentao->requestFix . 'getmodel' . $this->zentao->requestFix; - $modelAPI .= $module . $this->zentao->requestFix . $method . $this->zentao->requestFix; - $modelAPI .= $vars; - $modelAPI = rtrim($modelAPI, $this->zentao->requestFix) . '.json'; - $modelAPI = $this->appendSession($modelAPI); - } - return $modelAPI; - } - - /** - * Start session - * - * @access public - * @return void - */ - public function startSession() - { - $this->session = null; - $this->session = $this->httpGet($this->setSessionAPI()); - } - - /** - * Login. - * - * @access public - * @return void - */ - public function login() - { - $loginAPI = $this->setLoginAPI(); - $authHash = md5($this->zentao->password . $this->session->rand); - $loginAPI .= "&account={$this->zentao->account}&password=$authHash"; - $this->httpGet($loginAPI); - } - - /** - * Fetch one method of a module's control. - * - * @param string $module the module name - * @param string $method the methhod name - * @param string $vars the vars to passwd - * @access public - * @return void - */ - public function fetch($module, $method = 'index', $vars = '') - { - return $this->httpGet($this->setControlAPI($module, $method, $vars)); - } - - /** - * Fetch one method of a module's model. - * - * @param string $module the module name - * @param string $method the methhod name - * @param string $vars the vars to passwd - * @access public - * @return void - */ - public function fetchModel($module, $method, $vars = '') - { - return $this->httpGet($this->setModelAPI($module, $method, $vars)); - } - - /** - * Get a api and check it. - * - * @param string $url - * @access private - * @return bool - */ - private function httpGet($url) - { - $this->agent->fetch($url); - $result = json_decode($this->agent->results); - if($result->status != 'success') return false; - if(isset($result->data) and md5($result->data) != $result->md5) return false; - if(isset($result->data)) return json_decode($result->data); - return true; - } - - /** - * Fetch one method of a module's control. - * - * @param string $module the module name - * @param string $method the methhod name - * @param array $vars the vars to passwd - * @access public - * @return void - */ - public function post($module, $method = 'index', $vars = array()) - { - return $this->httpPost($this->setControlAPI($module, $method), $vars); - } - - /** - * Post. - * - * @param string $url - * @access private - * @return bool - */ - private function httpPost($url, $vars) - { - $this->agent->submit($url, $vars); - $result = json_decode($this->agent->results); - if($result->status != 'success') return false; - if(isset($result->data) and md5($result->data) != $result->md5) return false; - if(isset($result->data)) return json_decode($result->data); - return true; - } - - /** - * Append session param to the url. - * - * @param string $url - * @access private - * @return string - */ - private function appendSession($url) - { - if(strrpos($url, '&') === false) $url .= '?'; - if($this->session) $url .= '&' . $this->session->sessionName . '=' . $this->session->sessionID; - return str_replace('?&', '?', $url); - } -} -?> - -Copyright (c): 1999-2008 New Digital Group, all rights reserved -Version: 1.2.4 - - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You may contact the author of Snoopy by e-mail at: -monte@ohrt.com - -The latest version of Snoopy can be obtained from: -http://snoopy.sourceforge.net/ - -*************************************************/ - -class Snoopy -{ - /**** Public variables ****/ - - /* user definable vars */ - - var $host = "www.php.net"; // host name we are connecting to - var $port = 80; // port we are connecting to - var $proxy_host = ""; // proxy host to use - var $proxy_port = ""; // proxy port to use - var $proxy_user = ""; // proxy user to use - var $proxy_pass = ""; // proxy password to use - - var $agent = "Snoopy v1.2.4"; // agent we masquerade as - var $referer = ""; // referer info to pass - var $cookies = array(); // array of cookies to pass - // $cookies["username"]="joe"; - var $rawheaders = array(); // array of raw headers to send - // $rawheaders["Content-type"]="text/html"; - - var $maxredirs = 5; // http redirection depth maximum. 0 = disallow - var $lastredirectaddr = ""; // contains address of last redirected address - var $offsiteok = true; // allows redirection off-site - var $maxframes = 0; // frame content depth maximum. 0 = disallow - var $expandlinks = true; // expand links to fully qualified URLs. - // this only applies to fetchlinks() - // submitlinks(), and submittext() - var $passcookies = true; // pass set cookies back through redirects - // NOTE: this currently does not respect - // dates, domains or paths. - - var $user = ""; // user for http authentication - var $pass = ""; // password for http authentication - - // http accept types - var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; - - var $results = ""; // where the content is put - - var $error = ""; // error messages sent here - var $response_code = ""; // response code returned from server - var $headers = array(); // headers returned from server sent here - var $maxlength = 500000; // max return data length (body) - var $read_timeout = 0; // timeout on read operations, in seconds - // supported only since PHP 4 Beta 4 - // set to 0 to disallow timeouts - var $timed_out = false; // if a read operation timed out - var $status = 0; // http request status - - var $temp_dir = "/tmp"; // temporary directory that the webserver - // has permission to write to. - // under Windows, this should be C:\temp - - var $curl_path = "/usr/local/bin/curl"; - // Snoopy will use cURL for fetching - // SSL content if a full system path to - // the cURL binary is supplied here. - // set to false if you do not have - // cURL installed. See http://curl.haxx.se - // for details on installing cURL. - // Snoopy does *not* use the cURL - // library functions built into php, - // as these functions are not stable - // as of this Snoopy release. - - /**** Private variables ****/ - - var $_maxlinelen = 4096; // max line length (headers) - - var $_httpmethod = "GET"; // default http request method - var $_httpversion = "HTTP/1.0"; // default http request version - var $_submit_method = "POST"; // default submit method - var $_submit_type = "application/x-www-form-urlencoded"; // default submit type - var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type - var $_redirectaddr = false; // will be set if page fetched is a redirect - var $_redirectdepth = 0; // increments on an http redirect - var $_frameurls = array(); // frame src urls - var $_framedepth = 0; // increments on frame depth - - var $_isproxy = false; // set if using a proxy server - var $_fp_timeout = 30; // timeout for socket connection - -/*======================================================================*\ - Function: fetch - Purpose: fetch the contents of a web page - (and possibly other protocols in the - future like ftp, nntp, gopher, etc.) - Input: $URI the location of the page to fetch - Output: $this->results the output text from the fetch -\*======================================================================*/ - - function fetch($URI) - { - - //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS); - $URI_PARTS = parse_url($URI); - if (!empty($URI_PARTS["user"])) - $this->user = $URI_PARTS["user"]; - if (!empty($URI_PARTS["pass"])) - $this->pass = $URI_PARTS["pass"]; - if (empty($URI_PARTS["query"])) - $URI_PARTS["query"] = ''; - if (empty($URI_PARTS["path"])) - $URI_PARTS["path"] = ''; - - switch(strtolower($URI_PARTS["scheme"])) - { - case "http": - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_connect($fp)) - { - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httprequest($URI,$fp,$URI,$this->_httpmethod); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httprequest($path, $fp, $URI, $this->_httpmethod); - } - - $this->_disconnect($fp); - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - $this->fetch($this->_redirectaddr); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - } - else - { - return false; - } - return true; - break; - case "https": - if(!$this->curl_path) - return false; - if(function_exists("is_executable")) - if (!is_executable($this->curl_path)) - return false; - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httpsrequest($URI,$URI,$this->_httpmethod); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httpsrequest($path, $URI, $this->_httpmethod); - } - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - $this->fetch($this->_redirectaddr); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - return true; - break; - default: - // not a valid protocol - $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; - return false; - break; - } - return true; - } - -/*======================================================================*\ - Function: submit - Purpose: submit an http form - Input: $URI the location to post the data - $formvars the formvars to use. - format: $formvars["var"] = "val"; - $formfiles an array of files to submit - format: $formfiles["var"] = "/dir/filename.ext"; - Output: $this->results the text output from the post -\*======================================================================*/ - - function submit($URI, $formvars="", $formfiles="") - { - unset($postdata); - - $postdata = $this->_prepare_post_body($formvars, $formfiles); - - $URI_PARTS = parse_url($URI); - if (!empty($URI_PARTS["user"])) - $this->user = $URI_PARTS["user"]; - if (!empty($URI_PARTS["pass"])) - $this->pass = $URI_PARTS["pass"]; - if (empty($URI_PARTS["query"])) - $URI_PARTS["query"] = ''; - if (empty($URI_PARTS["path"])) - $URI_PARTS["path"] = ''; - - switch(strtolower($URI_PARTS["scheme"])) - { - case "http": - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_connect($fp)) - { - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - - $this->_disconnect($fp); - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) - $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); - - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - if( strpos( $this->_redirectaddr, "?" ) > 0 ) - $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get - else - $this->submit($this->_redirectaddr,$formvars, $formfiles); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - - } - else - { - return false; - } - return true; - break; - case "https": - if(!$this->curl_path) - return false; - if(function_exists("is_executable")) - if (!is_executable($this->curl_path)) - return false; - $this->host = $URI_PARTS["host"]; - if(!empty($URI_PARTS["port"])) - $this->port = $URI_PARTS["port"]; - if($this->_isproxy) - { - // using proxy, send entire URI - $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - else - { - $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); - // no proxy, send only the path - $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata); - } - - if($this->_redirectaddr) - { - /* url was redirected, check if we've hit the max depth */ - if($this->maxredirs > $this->_redirectdepth) - { - if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) - $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); - - // only follow redirect if it's on this site, or offsiteok is true - if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) - { - /* follow the redirect */ - $this->_redirectdepth++; - $this->lastredirectaddr=$this->_redirectaddr; - if( strpos( $this->_redirectaddr, "?" ) > 0 ) - $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get - else - $this->submit($this->_redirectaddr,$formvars, $formfiles); - } - } - } - - if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) - { - $frameurls = $this->_frameurls; - $this->_frameurls = array(); - - while(list(,$frameurl) = each($frameurls)) - { - if($this->_framedepth < $this->maxframes) - { - $this->fetch($frameurl); - $this->_framedepth++; - } - else - break; - } - } - return true; - break; - - default: - // not a valid protocol - $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; - return false; - break; - } - return true; - } - -/*======================================================================*\ - Function: fetchlinks - Purpose: fetch the links from a web page - Input: $URI where you are fetching from - Output: $this->results an array of the URLs -\*======================================================================*/ - - function fetchlinks($URI) - { - if ($this->fetch($URI)) - { - if($this->lastredirectaddr) - $URI = $this->lastredirectaddr; - if(is_array($this->results)) - { - for($x=0;$xresults);$x++) - $this->results[$x] = $this->_striplinks($this->results[$x]); - } - else - $this->results = $this->_striplinks($this->results); - - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results, $URI); - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: fetchform - Purpose: fetch the form elements from a web page - Input: $URI where you are fetching from - Output: $this->results the resulting html form -\*======================================================================*/ - - function fetchform($URI) - { - - if ($this->fetch($URI)) - { - - if(is_array($this->results)) - { - for($x=0;$xresults);$x++) - $this->results[$x] = $this->_stripform($this->results[$x]); - } - else - $this->results = $this->_stripform($this->results); - - return true; - } - else - return false; - } - - -/*======================================================================*\ - Function: fetchtext - Purpose: fetch the text from a web page, stripping the links - Input: $URI where you are fetching from - Output: $this->results the text from the web page -\*======================================================================*/ - - function fetchtext($URI) - { - if($this->fetch($URI)) - { - if(is_array($this->results)) - { - for($x=0;$xresults);$x++) - $this->results[$x] = $this->_striptext($this->results[$x]); - } - else - $this->results = $this->_striptext($this->results); - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: submitlinks - Purpose: grab links from a form submission - Input: $URI where you are submitting from - Output: $this->results an array of the links from the post -\*======================================================================*/ - - function submitlinks($URI, $formvars="", $formfiles="") - { - if($this->submit($URI,$formvars, $formfiles)) - { - if($this->lastredirectaddr) - $URI = $this->lastredirectaddr; - if(is_array($this->results)) - { - for($x=0;$xresults);$x++) - { - $this->results[$x] = $this->_striplinks($this->results[$x]); - if($this->expandlinks) - $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); - } - } - else - { - $this->results = $this->_striplinks($this->results); - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results,$URI); - } - return true; - } - else - return false; - } - -/*======================================================================*\ - Function: submittext - Purpose: grab text from a form submission - Input: $URI where you are submitting from - Output: $this->results the text from the web page -\*======================================================================*/ - - function submittext($URI, $formvars = "", $formfiles = "") - { - if($this->submit($URI,$formvars, $formfiles)) - { - if($this->lastredirectaddr) - $URI = $this->lastredirectaddr; - if(is_array($this->results)) - { - for($x=0;$xresults);$x++) - { - $this->results[$x] = $this->_striptext($this->results[$x]); - if($this->expandlinks) - $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); - } - } - else - { - $this->results = $this->_striptext($this->results); - if($this->expandlinks) - $this->results = $this->_expandlinks($this->results,$URI); - } - return true; - } - else - return false; - } - - - -/*======================================================================*\ - Function: set_submit_multipart - Purpose: Set the form submission content type to - multipart/form-data -\*======================================================================*/ - function set_submit_multipart() - { - $this->_submit_type = "multipart/form-data"; - } - - -/*======================================================================*\ - Function: set_submit_normal - Purpose: Set the form submission content type to - application/x-www-form-urlencoded -\*======================================================================*/ - function set_submit_normal() - { - $this->_submit_type = "application/x-www-form-urlencoded"; - } - - - - -/*======================================================================*\ - Private functions -\*======================================================================*/ - - -/*======================================================================*\ - Function: _striplinks - Purpose: strip the hyperlinks from an html document - Input: $document document to strip. - Output: $match an array of the links -\*======================================================================*/ - - function _striplinks($document) - { - preg_match_all("'<\s*a\s.*?href\s*=\s* # find ]+)) # if quote found, match up to next matching - # quote, otherwise match up to next space - 'isx",$document,$links); - - - // catenate the non-empty matches from the conditional subpattern - - while(list($key,$val) = each($links[2])) - { - if(!empty($val)) - $match[] = $val; - } - - while(list($key,$val) = each($links[3])) - { - if(!empty($val)) - $match[] = $val; - } - - // return the links - return $match; - } - -/*======================================================================*\ - Function: _stripform - Purpose: strip the form elements from an html document - Input: $document document to strip. - Output: $match an array of the links -\*======================================================================*/ - - function _stripform($document) - { - preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements); - - // catenate the matches - $match = implode("\r\n",$elements[0]); - - // return the links - return $match; - } - - - -/*======================================================================*\ - Function: _striptext - Purpose: strip the text from an html document - Input: $document document to strip. - Output: $text the resulting text -\*======================================================================*/ - - function _striptext($document) - { - - // I didn't use preg eval (//e) since that is only available in PHP 4.0. - // so, list your entities one by one here. I included some of the - // more common ones. - - $search = array("']*?>.*?'si", // strip out javascript - "'<[\/\!]*?[^<>]*?>'si", // strip out html tags - "'([\r\n])[\s]+'", // strip out white space - "'&(quot|#34|#034|#x22);'i", // replace html entities - "'&(amp|#38|#038|#x26);'i", // added hexadecimal values - "'&(lt|#60|#060|#x3c);'i", - "'&(gt|#62|#062|#x3e);'i", - "'&(nbsp|#160|#xa0);'i", - "'&(iexcl|#161);'i", - "'&(cent|#162);'i", - "'&(pound|#163);'i", - "'&(copy|#169);'i", - "'&(reg|#174);'i", - "'&(deg|#176);'i", - "'&(#39|#039|#x27);'", - "'&(euro|#8364);'i", // europe - "'&a(uml|UML);'", // german - "'&o(uml|UML);'", - "'&u(uml|UML);'", - "'&A(uml|UML);'", - "'&O(uml|UML);'", - "'&U(uml|UML);'", - "'ß'i", - ); - $replace = array( "", - "", - "\\1", - "\"", - "&", - "<", - ">", - " ", - chr(161), - chr(162), - chr(163), - chr(169), - chr(174), - chr(176), - chr(39), - chr(128), - "?", - "?", - "?", - "?", - "?", - "?", - "?", - ); - - $text = preg_replace($search,$replace,$document); - - return $text; - } - -/*======================================================================*\ - Function: _expandlinks - Purpose: expand each link into a fully qualified URL - Input: $links the links to qualify - $URI the full URI to get the base from - Output: $expandedLinks the expanded links -\*======================================================================*/ - - function _expandlinks($links,$URI) - { - - preg_match("/^[^\?]+/",$URI,$match); - - $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]); - $match = preg_replace("|/$|","",$match); - $match_part = parse_url($match); - $match_root = - $match_part["scheme"]."://".$match_part["host"]; - - $search = array( "|^http://".preg_quote($this->host)."|i", - "|^(\/)|i", - "|^(?!http://)(?!mailto:)|i", - "|/\./|", - "|/[^\/]+/\.\./|" - ); - - $replace = array( "", - $match_root."/", - $match."/", - "/", - "/" - ); - - $expandedLinks = preg_replace($search,$replace,$links); - - return $expandedLinks; - } - -/*======================================================================*\ - Function: _httprequest - Purpose: go get the http data from the server - Input: $url the url to fetch - $fp the current open file pointer - $URI the full URI - $body body contents to send if any (POST) - Output: -\*======================================================================*/ - - function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="") - { - $cookie_headers = ''; - if($this->passcookies && $this->_redirectaddr) - $this->setcookies(); - - $URI_PARTS = parse_url($URI); - if(empty($url)) - $url = "/"; - $headers = $http_method." ".$url." ".$this->_httpversion."\r\n"; - if(!empty($this->agent)) - $headers .= "User-Agent: ".$this->agent."\r\n"; - if(!empty($this->host) && !isset($this->rawheaders['Host'])) { - $headers .= "Host: ".$this->host; - if(!empty($this->port)) - $headers .= ":".$this->port; - $headers .= "\r\n"; - } - if(!empty($this->accept)) - $headers .= "Accept: ".$this->accept."\r\n"; - if(!empty($this->referer)) - $headers .= "Referer: ".$this->referer."\r\n"; - if(!empty($this->cookies)) - { - if(!is_array($this->cookies)) - $this->cookies = (array)$this->cookies; - - reset($this->cookies); - if ( count($this->cookies) > 0 ) { - $cookie_headers .= 'Cookie: '; - foreach ( $this->cookies as $cookieKey => $cookieVal ) { - $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; "; - } - $headers .= substr($cookie_headers,0,-2) . "\r\n"; - } - } - if(!empty($this->rawheaders)) - { - if(!is_array($this->rawheaders)) - $this->rawheaders = (array)$this->rawheaders; - while(list($headerKey,$headerVal) = each($this->rawheaders)) - $headers .= $headerKey.": ".$headerVal."\r\n"; - } - if(!empty($content_type)) { - $headers .= "Content-type: $content_type"; - if ($content_type == "multipart/form-data") - $headers .= "; boundary=".$this->_mime_boundary; - $headers .= "\r\n"; - } - if(!empty($body)) - $headers .= "Content-length: ".strlen($body)."\r\n"; - if(!empty($this->user) || !empty($this->pass)) - $headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n"; - - //add proxy auth headers - if(!empty($this->proxy_user)) - $headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n"; - - - $headers .= "\r\n"; - - // set the read timeout if needed - if ($this->read_timeout > 0) - socket_set_timeout($fp, $this->read_timeout); - $this->timed_out = false; - - fwrite($fp,$headers.$body,strlen($headers.$body)); - - $this->_redirectaddr = false; - unset($this->headers); - - while($currentHeader = fgets($fp,$this->_maxlinelen)) - { - if ($this->read_timeout > 0 && $this->_check_timeout($fp)) - { - $this->status=-100; - return false; - } - - if($currentHeader == "\r\n") - break; - - // if a header begins with Location: or URI:, set the redirect - if(preg_match("/^(Location:|URI:)/i",$currentHeader)) - { - // get URL portion of the redirect - preg_match("/^(Location:|URI:)[ ]+(.*)/i",chop($currentHeader),$matches); - // look for :// in the Location header to see if hostname is included - if(!preg_match("|\:\/\/|",$matches[2])) - { - // no host in the path, so prepend - $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; - // eliminate double slash - if(!preg_match("|^/|",$matches[2])) - $this->_redirectaddr .= "/".$matches[2]; - else - $this->_redirectaddr .= $matches[2]; - } - else - $this->_redirectaddr = $matches[2]; - } - - if(preg_match("|^HTTP/|",$currentHeader)) - { - if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status)) - { - $this->status= $status[1]; - } - $this->response_code = $currentHeader; - } - - $this->headers[] = $currentHeader; - } - - $results = ''; - do { - $_data = fread($fp, $this->maxlength); - if (strlen($_data) == 0) { - break; - } - $results .= $_data; - } while(true); - - if ($this->read_timeout > 0 && $this->_check_timeout($fp)) - { - $this->status=-100; - return false; - } - - // check if there is a a redirect meta tag - - if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) - - { - $this->_redirectaddr = $this->_expandlinks($match[1],$URI); - } - - // have we hit our frame depth and is there frame src to fetch? - if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) - { - $this->results[] = $results; - for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); - } - // have we already fetched framed content? - elseif(is_array($this->results)) - $this->results[] = $results; - // no framed content - else - $this->results = $results; - - return true; - } - -/*======================================================================*\ - Function: _httpsrequest - Purpose: go get the https data from the server using curl - Input: $url the url to fetch - $URI the full URI - $body body contents to send if any (POST) - Output: -\*======================================================================*/ - - function _httpsrequest($url,$URI,$http_method,$content_type="",$body="") - { - if($this->passcookies && $this->_redirectaddr) - $this->setcookies(); - - $headers = array(); - - $URI_PARTS = parse_url($URI); - if(empty($url)) - $url = "/"; - // GET ... header not needed for curl - //$headers[] = $http_method." ".$url." ".$this->_httpversion; - if(!empty($this->agent)) - $headers[] = "User-Agent: ".$this->agent; - if(!empty($this->host)) - if(!empty($this->port)) - $headers[] = "Host: ".$this->host.":".$this->port; - else - $headers[] = "Host: ".$this->host; - if(!empty($this->accept)) - $headers[] = "Accept: ".$this->accept; - if(!empty($this->referer)) - $headers[] = "Referer: ".$this->referer; - if(!empty($this->cookies)) - { - if(!is_array($this->cookies)) - $this->cookies = (array)$this->cookies; - - reset($this->cookies); - if ( count($this->cookies) > 0 ) { - $cookie_str = 'Cookie: '; - foreach ( $this->cookies as $cookieKey => $cookieVal ) { - $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; "; - } - $headers[] = substr($cookie_str,0,-2); - } - } - if(!empty($this->rawheaders)) - { - if(!is_array($this->rawheaders)) - $this->rawheaders = (array)$this->rawheaders; - while(list($headerKey,$headerVal) = each($this->rawheaders)) - $headers[] = $headerKey.": ".$headerVal; - } - if(!empty($content_type)) { - if ($content_type == "multipart/form-data") - $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary; - else - $headers[] = "Content-type: $content_type"; - } - if(!empty($body)) - $headers[] = "Content-length: ".strlen($body); - if(!empty($this->user) || !empty($this->pass)) - $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass); - - for($curr_header = 0; $curr_header < count($headers); $curr_header++) { - $safer_header = strtr( $headers[$curr_header], "\"", " " ); - $cmdline_params .= " -H \"".$safer_header."\""; - } - - if(!empty($body)) - $cmdline_params .= " -d \"$body\""; - - if($this->read_timeout > 0) - $cmdline_params .= " -m ".$this->read_timeout; - - $headerfile = tempnam($temp_dir, "sno"); - - exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return); - - if($return) - { - $this->error = "Error: cURL could not retrieve the document, error $return."; - return false; - } - - - $results = implode("\r\n",$results); - - $result_headers = file("$headerfile"); - - $this->_redirectaddr = false; - unset($this->headers); - - for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++) - { - - // if a header begins with Location: or URI:, set the redirect - if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader])) - { - // get URL portion of the redirect - preg_match("/^(Location: |URI:)\s+(.*)/",chop($result_headers[$currentHeader]),$matches); - // look for :// in the Location header to see if hostname is included - if(!preg_match("|\:\/\/|",$matches[2])) - { - // no host in the path, so prepend - $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; - // eliminate double slash - if(!preg_match("|^/|",$matches[2])) - $this->_redirectaddr .= "/".$matches[2]; - else - $this->_redirectaddr .= $matches[2]; - } - else - $this->_redirectaddr = $matches[2]; - } - - if(preg_match("|^HTTP/|",$result_headers[$currentHeader])) - $this->response_code = $result_headers[$currentHeader]; - - $this->headers[] = $result_headers[$currentHeader]; - } - - // check if there is a a redirect meta tag - - if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) - { - $this->_redirectaddr = $this->_expandlinks($match[1],$URI); - } - - // have we hit our frame depth and is there frame src to fetch? - if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) - { - $this->results[] = $results; - for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); - } - // have we already fetched framed content? - elseif(is_array($this->results)) - $this->results[] = $results; - // no framed content - else - $this->results = $results; - - unlink("$headerfile"); - - return true; - } - -/*======================================================================*\ - Function: setcookies() - Purpose: set cookies for a redirection -\*======================================================================*/ - - function setcookies() - { - for($x=0; $xheaders); $x++) - { - if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match)) - $this->cookies[$match[1]] = urldecode($match[2]); - } - } - - -/*======================================================================*\ - Function: _check_timeout - Purpose: checks whether timeout has occurred - Input: $fp file pointer -\*======================================================================*/ - - function _check_timeout($fp) - { - if ($this->read_timeout > 0) { - $fp_status = socket_get_status($fp); - if ($fp_status["timed_out"]) { - $this->timed_out = true; - return true; - } - } - return false; - } - -/*======================================================================*\ - Function: _connect - Purpose: make a socket connection - Input: $fp file pointer -\*======================================================================*/ - - function _connect(&$fp) - { - if(!empty($this->proxy_host) && !empty($this->proxy_port)) - { - $this->_isproxy = true; - - $host = $this->proxy_host; - $port = $this->proxy_port; - } - else - { - $host = $this->host; - $port = $this->port; - } - - $this->status = 0; - - if($fp = fsockopen( - $host, - $port, - $errno, - $errstr, - $this->_fp_timeout - )) - { - // socket connection succeeded - - return true; - } - else - { - // socket connection failed - $this->status = $errno; - switch($errno) - { - case -3: - $this->error="socket creation failed (-3)"; - case -4: - $this->error="dns lookup failure (-4)"; - case -5: - $this->error="connection refused or timed out (-5)"; - default: - $this->error="connection failed (".$errno.")"; - } - return false; - } - } -/*======================================================================*\ - Function: _disconnect - Purpose: disconnect a socket connection - Input: $fp file pointer -\*======================================================================*/ - - function _disconnect($fp) - { - return(fclose($fp)); - } - - -/*======================================================================*\ - Function: _prepare_post_body - Purpose: Prepare post body according to encoding type - Input: $formvars - form variables - $formfiles - form upload files - Output: post body -\*======================================================================*/ - - function _prepare_post_body($formvars, $formfiles) - { - settype($formvars, "array"); - settype($formfiles, "array"); - $postdata = ''; - - if (count($formvars) == 0 && count($formfiles) == 0) - return; - - switch ($this->_submit_type) { - case "application/x-www-form-urlencoded": - reset($formvars); - while(list($key,$val) = each($formvars)) { - if (is_array($val) || is_object($val)) { - while (list($cur_key, $cur_val) = each($val)) { - $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&"; - } - } else - $postdata .= urlencode($key)."=".urlencode($val)."&"; - } - break; - - case "multipart/form-data": - $this->_mime_boundary = "Snoopy".md5(uniqid(microtime())); - - reset($formvars); - while(list($key,$val) = each($formvars)) { - if (is_array($val) || is_object($val)) { - while (list($cur_key, $cur_val) = each($val)) { - $postdata .= "--".$this->_mime_boundary."\r\n"; - $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n"; - $postdata .= "$cur_val\r\n"; - } - } else { - $postdata .= "--".$this->_mime_boundary."\r\n"; - $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n"; - $postdata .= "$val\r\n"; - } - } - - reset($formfiles); - while (list($field_name, $file_names) = each($formfiles)) { - settype($file_names, "array"); - while (list(, $file_name) = each($file_names)) { - if (!is_readable($file_name)) continue; - - $fp = fopen($file_name, "r"); - $file_content = fread($fp, filesize($file_name)); - fclose($fp); - $base_name = basename($file_name); - - $postdata .= "--".$this->_mime_boundary."\r\n"; - $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n"; - $postdata .= "$file_content\r\n"; - } - } - $postdata .= "--".$this->_mime_boundary."--\r\n"; - break; - } - - return $postdata; - } -} -?> + + * @package API + * @version $Id$ + * @link http://www.zentao.net + */ +class ztclient +{ + public $configFile; + public $zentao; + public $agent; + public $session; + + /** + * The construce function. + * + * @param string $zentaoRoot the zentao root url + * @param string $account the login account + * @param string $password the passwod + * @access public + * @return void + */ + public function __construct($zentaoRoot = '', $account = '', $password = '') + { + $this->agent = new snoopy(); + + /* Assign to $this->zentao. */ + $this->zentao->root = rtrim($zentaoRoot, '/') . '/'; + $this->zentao->account = $account; + $this->zentao->password = md5($password); + + /* Load the remote settings. */ + $config = $this->getRemoteConfig(); + foreach($config as $key => $value) $this->zentao->$key = $value; + + $this->startSession(); + $this->login(); + } + + /** + * Get the settings through getconfig api from remote. + * + * @access private + * @return object + */ + private function getRemoteConfig() + { + $url = $this->zentao->root . '/index.php?mode=getconfig'; + $this->agent->fetchText($url); + $config = json_decode($this->agent->results); + return $config; + } + + /** + * Set the session api. + * + * @access private + * @return string the session api url. + */ + private function setSessionAPI() + { + return $this->setControlAPI('api', 'getsessionid'); + } + + /** + * Set the login api. + * + * @access private + * @return string the login api url. + */ + private function setLoginAPI() + { + return $this->setControlAPI('user', 'login'); + } + + /** + * Set the method api. + * + * @param string $module the module name + * @param string $method the methhod name + * @param string $vars the vars to passwd + * @access private + * @return string the control api string. + */ + private function setControlAPI($module, $method, $vars = '') + { + if($this->zentao->requestType == 'GET') + { + $controlAPI = $this->appendSession($this->zentao->root); + $controlAPI .= "&{$this->zentao->moduleVar}=$module&{$this->zentao->methodVar}=$method&{$this->zentao->viewVar}=json$vars"; + } + elseif($this->zentao->requestType == 'PATH_INFO') + { + $controlAPI = $this->zentao->root . $module . $this->zentao->requestFix . $method . $this->zentao->requestFix; + if($vars) + { + $vars = parse_str($vars); + foreach($vars as $var) $controlAPI .= $var . $this->zentao->requestFix; + } + $controlAPI = rtrim($controlAPI, $this->zentao->requestFix) . '.json'; + $controlAPI = $this->appendSession($controlAPI); + } + return $controlAPI; + } + + /** + * Set the method api. + * + * @param string $module the module name + * @param string $method the methhod name + * @param string $vars the vars to passed + * @access private + * @return string the model api string. + */ + private function setModelAPI($module, $method, $vars = '') + { + $vars = str_replace('&', ',', $vars); + if($this->zentao->requestType == 'GET') + { + $modelAPI = $this->appendSession($this->zentao->root); + $modelAPI .= "&{$this->zentao->moduleVar}=api&{$this->zentao->methodVar}=getModel&{$this->zentao->viewVar}=json"; + $modelAPI .="&module=$module&method=$method¶ms=$vars"; + } + elseif($this->zentao->requestType == 'PATH_INFO') + { + $modelAPI = $this->zentao->root . 'api' . $this->zentao->requestFix . 'getmodel' . $this->zentao->requestFix; + $modelAPI .= $module . $this->zentao->requestFix . $method . $this->zentao->requestFix; + $modelAPI .= $vars; + $modelAPI = rtrim($modelAPI, $this->zentao->requestFix) . '.json'; + $modelAPI = $this->appendSession($modelAPI); + } + return $modelAPI; + } + + /** + * Start session + * + * @access public + * @return void + */ + public function startSession() + { + $this->session = null; + $this->session = $this->httpGet($this->setSessionAPI()); + } + + /** + * Login. + * + * @access public + * @return void + */ + public function login() + { + $loginAPI = $this->setLoginAPI(); + $authHash = md5($this->zentao->password . $this->session->rand); + $loginAPI .= "&account={$this->zentao->account}&password=$authHash"; + $this->httpGet($loginAPI); + } + + /** + * Fetch one method of a module's control. + * + * @param string $module the module name + * @param string $method the methhod name + * @param string $vars the vars to passwd + * @access public + * @return void + */ + public function fetch($module, $method = 'index', $vars = '') + { + return $this->httpGet($this->setControlAPI($module, $method, $vars)); + } + + /** + * Fetch one method of a module's model. + * + * @param string $module the module name + * @param string $method the methhod name + * @param string $vars the vars to passwd + * @access public + * @return void + */ + public function fetchModel($module, $method, $vars = '') + { + return $this->httpGet($this->setModelAPI($module, $method, $vars)); + } + + /** + * Get a api and check it. + * + * @param string $url + * @access private + * @return bool + */ + private function httpGet($url) + { + $this->agent->fetch($url); + $result = json_decode($this->agent->results); + if($result->status != 'success') return false; + if(isset($result->data) and md5($result->data) != $result->md5) return false; + if(isset($result->data)) return json_decode($result->data); + return true; + } + + /** + * Fetch one method of a module's control. + * + * @param string $module the module name + * @param string $method the methhod name + * @param array $vars the vars to passwd + * @access public + * @return void + */ + public function post($module, $method = 'index', $vars = array()) + { + return $this->httpPost($this->setControlAPI($module, $method), $vars); + } + + /** + * Post. + * + * @param string $url + * @access private + * @return bool + */ + private function httpPost($url, $vars) + { + $this->agent->submit($url, $vars); + $result = json_decode($this->agent->results); + if($result->status != 'success') return false; + if(isset($result->data) and md5($result->data) != $result->md5) return false; + if(isset($result->data)) return json_decode($result->data); + return true; + } + + /** + * Append session param to the url. + * + * @param string $url + * @access private + * @return string + */ + private function appendSession($url) + { + if(strrpos($url, '&') === false) $url .= '?'; + if($this->session) $url .= '&' . $this->session->sessionName . '=' . $this->session->sessionID; + return str_replace('?&', '?', $url); + } +} +?> + +Copyright (c): 1999-2008 New Digital Group, all rights reserved +Version: 1.2.4 + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +You may contact the author of Snoopy by e-mail at: +monte@ohrt.com + +The latest version of Snoopy can be obtained from: +http://snoopy.sourceforge.net/ + +*************************************************/ + +class Snoopy +{ + /**** Public variables ****/ + + /* user definable vars */ + + var $host = "www.php.net"; // host name we are connecting to + var $port = 80; // port we are connecting to + var $proxy_host = ""; // proxy host to use + var $proxy_port = ""; // proxy port to use + var $proxy_user = ""; // proxy user to use + var $proxy_pass = ""; // proxy password to use + + var $agent = "Snoopy v1.2.4"; // agent we masquerade as + var $referer = ""; // referer info to pass + var $cookies = array(); // array of cookies to pass + // $cookies["username"]="joe"; + var $rawheaders = array(); // array of raw headers to send + // $rawheaders["Content-type"]="text/html"; + + var $maxredirs = 5; // http redirection depth maximum. 0 = disallow + var $lastredirectaddr = ""; // contains address of last redirected address + var $offsiteok = true; // allows redirection off-site + var $maxframes = 0; // frame content depth maximum. 0 = disallow + var $expandlinks = true; // expand links to fully qualified URLs. + // this only applies to fetchlinks() + // submitlinks(), and submittext() + var $passcookies = true; // pass set cookies back through redirects + // NOTE: this currently does not respect + // dates, domains or paths. + + var $user = ""; // user for http authentication + var $pass = ""; // password for http authentication + + // http accept types + var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + + var $results = ""; // where the content is put + + var $error = ""; // error messages sent here + var $response_code = ""; // response code returned from server + var $headers = array(); // headers returned from server sent here + var $maxlength = 500000; // max return data length (body) + var $read_timeout = 0; // timeout on read operations, in seconds + // supported only since PHP 4 Beta 4 + // set to 0 to disallow timeouts + var $timed_out = false; // if a read operation timed out + var $status = 0; // http request status + + var $temp_dir = "/tmp"; // temporary directory that the webserver + // has permission to write to. + // under Windows, this should be C:\temp + + var $curl_path = "/usr/local/bin/curl"; + // Snoopy will use cURL for fetching + // SSL content if a full system path to + // the cURL binary is supplied here. + // set to false if you do not have + // cURL installed. See http://curl.haxx.se + // for details on installing cURL. + // Snoopy does *not* use the cURL + // library functions built into php, + // as these functions are not stable + // as of this Snoopy release. + + /**** Private variables ****/ + + var $_maxlinelen = 4096; // max line length (headers) + + var $_httpmethod = "GET"; // default http request method + var $_httpversion = "HTTP/1.0"; // default http request version + var $_submit_method = "POST"; // default submit method + var $_submit_type = "application/x-www-form-urlencoded"; // default submit type + var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type + var $_redirectaddr = false; // will be set if page fetched is a redirect + var $_redirectdepth = 0; // increments on an http redirect + var $_frameurls = array(); // frame src urls + var $_framedepth = 0; // increments on frame depth + + var $_isproxy = false; // set if using a proxy server + var $_fp_timeout = 30; // timeout for socket connection + +/*======================================================================*\ + Function: fetch + Purpose: fetch the contents of a web page + (and possibly other protocols in the + future like ftp, nntp, gopher, etc.) + Input: $URI the location of the page to fetch + Output: $this->results the output text from the fetch +\*======================================================================*/ + + function fetch($URI) + { + + //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS); + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_httpmethod); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI,$URI,$this->_httpmethod); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_httpmethod); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + $this->fetch($this->_redirectaddr); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: submit + Purpose: submit an http form + Input: $URI the location to post the data + $formvars the formvars to use. + format: $formvars["var"] = "val"; + $formfiles an array of files to submit + format: $formfiles["var"] = "/dir/filename.ext"; + Output: $this->results the text output from the post +\*======================================================================*/ + + function submit($URI, $formvars="", $formfiles="") + { + unset($postdata); + + $postdata = $this->_prepare_post_body($formvars, $formfiles); + + $URI_PARTS = parse_url($URI); + if (!empty($URI_PARTS["user"])) + $this->user = $URI_PARTS["user"]; + if (!empty($URI_PARTS["pass"])) + $this->pass = $URI_PARTS["pass"]; + if (empty($URI_PARTS["query"])) + $URI_PARTS["query"] = ''; + if (empty($URI_PARTS["path"])) + $URI_PARTS["path"] = ''; + + switch(strtolower($URI_PARTS["scheme"])) + { + case "http": + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_connect($fp)) + { + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + $this->_disconnect($fp); + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + + } + else + { + return false; + } + return true; + break; + case "https": + if(!$this->curl_path) + return false; + if(function_exists("is_executable")) + if (!is_executable($this->curl_path)) + return false; + $this->host = $URI_PARTS["host"]; + if(!empty($URI_PARTS["port"])) + $this->port = $URI_PARTS["port"]; + if($this->_isproxy) + { + // using proxy, send entire URI + $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + else + { + $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : ""); + // no proxy, send only the path + $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata); + } + + if($this->_redirectaddr) + { + /* url was redirected, check if we've hit the max depth */ + if($this->maxredirs > $this->_redirectdepth) + { + if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr)) + $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]); + + // only follow redirect if it's on this site, or offsiteok is true + if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok) + { + /* follow the redirect */ + $this->_redirectdepth++; + $this->lastredirectaddr=$this->_redirectaddr; + if( strpos( $this->_redirectaddr, "?" ) > 0 ) + $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get + else + $this->submit($this->_redirectaddr,$formvars, $formfiles); + } + } + } + + if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0) + { + $frameurls = $this->_frameurls; + $this->_frameurls = array(); + + while(list(,$frameurl) = each($frameurls)) + { + if($this->_framedepth < $this->maxframes) + { + $this->fetch($frameurl); + $this->_framedepth++; + } + else + break; + } + } + return true; + break; + + default: + // not a valid protocol + $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n'; + return false; + break; + } + return true; + } + +/*======================================================================*\ + Function: fetchlinks + Purpose: fetch the links from a web page + Input: $URI where you are fetching from + Output: $this->results an array of the URLs +\*======================================================================*/ + + function fetchlinks($URI) + { + if ($this->fetch($URI)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striplinks($this->results[$x]); + } + else + $this->results = $this->_striplinks($this->results); + + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results, $URI); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: fetchform + Purpose: fetch the form elements from a web page + Input: $URI where you are fetching from + Output: $this->results the resulting html form +\*======================================================================*/ + + function fetchform($URI) + { + + if ($this->fetch($URI)) + { + + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_stripform($this->results[$x]); + } + else + $this->results = $this->_stripform($this->results); + + return true; + } + else + return false; + } + + +/*======================================================================*\ + Function: fetchtext + Purpose: fetch the text from a web page, stripping the links + Input: $URI where you are fetching from + Output: $this->results the text from the web page +\*======================================================================*/ + + function fetchtext($URI) + { + if($this->fetch($URI)) + { + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + $this->results[$x] = $this->_striptext($this->results[$x]); + } + else + $this->results = $this->_striptext($this->results); + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submitlinks + Purpose: grab links from a form submission + Input: $URI where you are submitting from + Output: $this->results an array of the links from the post +\*======================================================================*/ + + function submitlinks($URI, $formvars="", $formfiles="") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striplinks($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striplinks($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + +/*======================================================================*\ + Function: submittext + Purpose: grab text from a form submission + Input: $URI where you are submitting from + Output: $this->results the text from the web page +\*======================================================================*/ + + function submittext($URI, $formvars = "", $formfiles = "") + { + if($this->submit($URI,$formvars, $formfiles)) + { + if($this->lastredirectaddr) + $URI = $this->lastredirectaddr; + if(is_array($this->results)) + { + for($x=0;$xresults);$x++) + { + $this->results[$x] = $this->_striptext($this->results[$x]); + if($this->expandlinks) + $this->results[$x] = $this->_expandlinks($this->results[$x],$URI); + } + } + else + { + $this->results = $this->_striptext($this->results); + if($this->expandlinks) + $this->results = $this->_expandlinks($this->results,$URI); + } + return true; + } + else + return false; + } + + + +/*======================================================================*\ + Function: set_submit_multipart + Purpose: Set the form submission content type to + multipart/form-data +\*======================================================================*/ + function set_submit_multipart() + { + $this->_submit_type = "multipart/form-data"; + } + + +/*======================================================================*\ + Function: set_submit_normal + Purpose: Set the form submission content type to + application/x-www-form-urlencoded +\*======================================================================*/ + function set_submit_normal() + { + $this->_submit_type = "application/x-www-form-urlencoded"; + } + + + + +/*======================================================================*\ + Private functions +\*======================================================================*/ + + +/*======================================================================*\ + Function: _striplinks + Purpose: strip the hyperlinks from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _striplinks($document) + { + preg_match_all("'<\s*a\s.*?href\s*=\s* # find ]+)) # if quote found, match up to next matching + # quote, otherwise match up to next space + 'isx",$document,$links); + + + // catenate the non-empty matches from the conditional subpattern + + while(list($key,$val) = each($links[2])) + { + if(!empty($val)) + $match[] = $val; + } + + while(list($key,$val) = each($links[3])) + { + if(!empty($val)) + $match[] = $val; + } + + // return the links + return $match; + } + +/*======================================================================*\ + Function: _stripform + Purpose: strip the form elements from an html document + Input: $document document to strip. + Output: $match an array of the links +\*======================================================================*/ + + function _stripform($document) + { + preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements); + + // catenate the matches + $match = implode("\r\n",$elements[0]); + + // return the links + return $match; + } + + + +/*======================================================================*\ + Function: _striptext + Purpose: strip the text from an html document + Input: $document document to strip. + Output: $text the resulting text +\*======================================================================*/ + + function _striptext($document) + { + + // I didn't use preg eval (//e) since that is only available in PHP 4.0. + // so, list your entities one by one here. I included some of the + // more common ones. + + $search = array("']*?>.*?'si", // strip out javascript + "'<[\/\!]*?[^<>]*?>'si", // strip out html tags + "'([\r\n])[\s]+'", // strip out white space + "'&(quot|#34|#034|#x22);'i", // replace html entities + "'&(amp|#38|#038|#x26);'i", // added hexadecimal values + "'&(lt|#60|#060|#x3c);'i", + "'&(gt|#62|#062|#x3e);'i", + "'&(nbsp|#160|#xa0);'i", + "'&(iexcl|#161);'i", + "'&(cent|#162);'i", + "'&(pound|#163);'i", + "'&(copy|#169);'i", + "'&(reg|#174);'i", + "'&(deg|#176);'i", + "'&(#39|#039|#x27);'", + "'&(euro|#8364);'i", // europe + "'&a(uml|UML);'", // german + "'&o(uml|UML);'", + "'&u(uml|UML);'", + "'&A(uml|UML);'", + "'&O(uml|UML);'", + "'&U(uml|UML);'", + "'ß'i", + ); + $replace = array( "", + "", + "\\1", + "\"", + "&", + "<", + ">", + " ", + chr(161), + chr(162), + chr(163), + chr(169), + chr(174), + chr(176), + chr(39), + chr(128), + "?", + "?", + "?", + "?", + "?", + "?", + "?", + ); + + $text = preg_replace($search,$replace,$document); + + return $text; + } + +/*======================================================================*\ + Function: _expandlinks + Purpose: expand each link into a fully qualified URL + Input: $links the links to qualify + $URI the full URI to get the base from + Output: $expandedLinks the expanded links +\*======================================================================*/ + + function _expandlinks($links,$URI) + { + + preg_match("/^[^\?]+/",$URI,$match); + + $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]); + $match = preg_replace("|/$|","",$match); + $match_part = parse_url($match); + $match_root = + $match_part["scheme"]."://".$match_part["host"]; + + $search = array( "|^http://".preg_quote($this->host)."|i", + "|^(\/)|i", + "|^(?!http://)(?!mailto:)|i", + "|/\./|", + "|/[^\/]+/\.\./|" + ); + + $replace = array( "", + $match_root."/", + $match."/", + "/", + "/" + ); + + $expandedLinks = preg_replace($search,$replace,$links); + + return $expandedLinks; + } + +/*======================================================================*\ + Function: _httprequest + Purpose: go get the http data from the server + Input: $url the url to fetch + $fp the current open file pointer + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="") + { + $cookie_headers = ''; + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + $headers = $http_method." ".$url." ".$this->_httpversion."\r\n"; + if(!empty($this->agent)) + $headers .= "User-Agent: ".$this->agent."\r\n"; + if(!empty($this->host) && !isset($this->rawheaders['Host'])) { + $headers .= "Host: ".$this->host; + if(!empty($this->port)) + $headers .= ":".$this->port; + $headers .= "\r\n"; + } + if(!empty($this->accept)) + $headers .= "Accept: ".$this->accept."\r\n"; + if(!empty($this->referer)) + $headers .= "Referer: ".$this->referer."\r\n"; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_headers .= 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers .= substr($cookie_headers,0,-2) . "\r\n"; + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers .= $headerKey.": ".$headerVal."\r\n"; + } + if(!empty($content_type)) { + $headers .= "Content-type: $content_type"; + if ($content_type == "multipart/form-data") + $headers .= "; boundary=".$this->_mime_boundary; + $headers .= "\r\n"; + } + if(!empty($body)) + $headers .= "Content-length: ".strlen($body)."\r\n"; + if(!empty($this->user) || !empty($this->pass)) + $headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n"; + + //add proxy auth headers + if(!empty($this->proxy_user)) + $headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n"; + + + $headers .= "\r\n"; + + // set the read timeout if needed + if ($this->read_timeout > 0) + socket_set_timeout($fp, $this->read_timeout); + $this->timed_out = false; + + fwrite($fp,$headers.$body,strlen($headers.$body)); + + $this->_redirectaddr = false; + unset($this->headers); + + while($currentHeader = fgets($fp,$this->_maxlinelen)) + { + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + if($currentHeader == "\r\n") + break; + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location:|URI:)/i",$currentHeader)) + { + // get URL portion of the redirect + preg_match("/^(Location:|URI:)[ ]+(.*)/i",chop($currentHeader),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$currentHeader)) + { + if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status)) + { + $this->status= $status[1]; + } + $this->response_code = $currentHeader; + } + + $this->headers[] = $currentHeader; + } + + $results = ''; + do { + $_data = fread($fp, $this->maxlength); + if (strlen($_data) == 0) { + break; + } + $results .= $_data; + } while(true); + + if ($this->read_timeout > 0 && $this->_check_timeout($fp)) + { + $this->status=-100; + return false; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + return true; + } + +/*======================================================================*\ + Function: _httpsrequest + Purpose: go get the https data from the server using curl + Input: $url the url to fetch + $URI the full URI + $body body contents to send if any (POST) + Output: +\*======================================================================*/ + + function _httpsrequest($url,$URI,$http_method,$content_type="",$body="") + { + if($this->passcookies && $this->_redirectaddr) + $this->setcookies(); + + $headers = array(); + + $URI_PARTS = parse_url($URI); + if(empty($url)) + $url = "/"; + // GET ... header not needed for curl + //$headers[] = $http_method." ".$url." ".$this->_httpversion; + if(!empty($this->agent)) + $headers[] = "User-Agent: ".$this->agent; + if(!empty($this->host)) + if(!empty($this->port)) + $headers[] = "Host: ".$this->host.":".$this->port; + else + $headers[] = "Host: ".$this->host; + if(!empty($this->accept)) + $headers[] = "Accept: ".$this->accept; + if(!empty($this->referer)) + $headers[] = "Referer: ".$this->referer; + if(!empty($this->cookies)) + { + if(!is_array($this->cookies)) + $this->cookies = (array)$this->cookies; + + reset($this->cookies); + if ( count($this->cookies) > 0 ) { + $cookie_str = 'Cookie: '; + foreach ( $this->cookies as $cookieKey => $cookieVal ) { + $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; "; + } + $headers[] = substr($cookie_str,0,-2); + } + } + if(!empty($this->rawheaders)) + { + if(!is_array($this->rawheaders)) + $this->rawheaders = (array)$this->rawheaders; + while(list($headerKey,$headerVal) = each($this->rawheaders)) + $headers[] = $headerKey.": ".$headerVal; + } + if(!empty($content_type)) { + if ($content_type == "multipart/form-data") + $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary; + else + $headers[] = "Content-type: $content_type"; + } + if(!empty($body)) + $headers[] = "Content-length: ".strlen($body); + if(!empty($this->user) || !empty($this->pass)) + $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass); + + for($curr_header = 0; $curr_header < count($headers); $curr_header++) { + $safer_header = strtr( $headers[$curr_header], "\"", " " ); + $cmdline_params .= " -H \"".$safer_header."\""; + } + + if(!empty($body)) + $cmdline_params .= " -d \"$body\""; + + if($this->read_timeout > 0) + $cmdline_params .= " -m ".$this->read_timeout; + + $headerfile = tempnam($temp_dir, "sno"); + + exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return); + + if($return) + { + $this->error = "Error: cURL could not retrieve the document, error $return."; + return false; + } + + + $results = implode("\r\n",$results); + + $result_headers = file("$headerfile"); + + $this->_redirectaddr = false; + unset($this->headers); + + for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++) + { + + // if a header begins with Location: or URI:, set the redirect + if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader])) + { + // get URL portion of the redirect + preg_match("/^(Location: |URI:)\s+(.*)/",chop($result_headers[$currentHeader]),$matches); + // look for :// in the Location header to see if hostname is included + if(!preg_match("|\:\/\/|",$matches[2])) + { + // no host in the path, so prepend + $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port; + // eliminate double slash + if(!preg_match("|^/|",$matches[2])) + $this->_redirectaddr .= "/".$matches[2]; + else + $this->_redirectaddr .= $matches[2]; + } + else + $this->_redirectaddr = $matches[2]; + } + + if(preg_match("|^HTTP/|",$result_headers[$currentHeader])) + $this->response_code = $result_headers[$currentHeader]; + + $this->headers[] = $result_headers[$currentHeader]; + } + + // check if there is a a redirect meta tag + + if(preg_match("']*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match)) + { + $this->_redirectaddr = $this->_expandlinks($match[1],$URI); + } + + // have we hit our frame depth and is there frame src to fetch? + if(($this->_framedepth < $this->maxframes) && preg_match_all("']+)'i",$results,$match)) + { + $this->results[] = $results; + for($x=0; $x_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host); + } + // have we already fetched framed content? + elseif(is_array($this->results)) + $this->results[] = $results; + // no framed content + else + $this->results = $results; + + unlink("$headerfile"); + + return true; + } + +/*======================================================================*\ + Function: setcookies() + Purpose: set cookies for a redirection +\*======================================================================*/ + + function setcookies() + { + for($x=0; $xheaders); $x++) + { + if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match)) + $this->cookies[$match[1]] = urldecode($match[2]); + } + } + + +/*======================================================================*\ + Function: _check_timeout + Purpose: checks whether timeout has occurred + Input: $fp file pointer +\*======================================================================*/ + + function _check_timeout($fp) + { + if ($this->read_timeout > 0) { + $fp_status = socket_get_status($fp); + if ($fp_status["timed_out"]) { + $this->timed_out = true; + return true; + } + } + return false; + } + +/*======================================================================*\ + Function: _connect + Purpose: make a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _connect(&$fp) + { + if(!empty($this->proxy_host) && !empty($this->proxy_port)) + { + $this->_isproxy = true; + + $host = $this->proxy_host; + $port = $this->proxy_port; + } + else + { + $host = $this->host; + $port = $this->port; + } + + $this->status = 0; + + if($fp = fsockopen( + $host, + $port, + $errno, + $errstr, + $this->_fp_timeout + )) + { + // socket connection succeeded + + return true; + } + else + { + // socket connection failed + $this->status = $errno; + switch($errno) + { + case -3: + $this->error="socket creation failed (-3)"; + case -4: + $this->error="dns lookup failure (-4)"; + case -5: + $this->error="connection refused or timed out (-5)"; + default: + $this->error="connection failed (".$errno.")"; + } + return false; + } + } +/*======================================================================*\ + Function: _disconnect + Purpose: disconnect a socket connection + Input: $fp file pointer +\*======================================================================*/ + + function _disconnect($fp) + { + return(fclose($fp)); + } + + +/*======================================================================*\ + Function: _prepare_post_body + Purpose: Prepare post body according to encoding type + Input: $formvars - form variables + $formfiles - form upload files + Output: post body +\*======================================================================*/ + + function _prepare_post_body($formvars, $formfiles) + { + settype($formvars, "array"); + settype($formfiles, "array"); + $postdata = ''; + + if (count($formvars) == 0 && count($formfiles) == 0) + return; + + switch ($this->_submit_type) { + case "application/x-www-form-urlencoded": + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&"; + } + } else + $postdata .= urlencode($key)."=".urlencode($val)."&"; + } + break; + + case "multipart/form-data": + $this->_mime_boundary = "Snoopy".md5(uniqid(microtime())); + + reset($formvars); + while(list($key,$val) = each($formvars)) { + if (is_array($val) || is_object($val)) { + while (list($cur_key, $cur_val) = each($val)) { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n"; + $postdata .= "$cur_val\r\n"; + } + } else { + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n"; + $postdata .= "$val\r\n"; + } + } + + reset($formfiles); + while (list($field_name, $file_names) = each($formfiles)) { + settype($file_names, "array"); + while (list(, $file_name) = each($file_names)) { + if (!is_readable($file_name)) continue; + + $fp = fopen($file_name, "r"); + $file_content = fread($fp, filesize($file_name)); + fclose($fp); + $base_name = basename($file_name); + + $postdata .= "--".$this->_mime_boundary."\r\n"; + $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n"; + $postdata .= "$file_content\r\n"; + } + } + $postdata .= "--".$this->_mime_boundary."--\r\n"; + break; + } + + return $postdata; + } +} +?> diff --git a/lib/pclzip/pclzip.class.php b/lib/pclzip/pclzip.class.php index 4bf05a5236..e7facc1eaa 100644 --- a/lib/pclzip/pclzip.class.php +++ b/lib/pclzip/pclzip.class.php @@ -1,5694 +1,5694 @@ -zipname = $p_zipname; - $this->zip_fd = 0; - $this->magic_quotes_status = -1; - - // ----- Return - return; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // create($p_filelist, $p_add_dir="", $p_remove_dir="") - // create($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two different synopsis. The first one is historical. - // This method creates a Zip Archive. The Zip file is created in the - // filesystem. The files and directories indicated in $p_filelist - // are added in the archive. See the parameters description for the - // supported format of $p_filelist. - // When a directory is in the list, the directory and its content is added - // in the archive. - // In this synopsis, the function takes an optional variable list of - // options. See bellow the supported options. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function create($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove from the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); - if ($v_result != 1) { - return 0; - } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; - } - else if ($v_size > 2) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Invalid number / type of arguments"); - return 0; - } - } - } - - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); - - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); - - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { - - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } - - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } - - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } - - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); - return 0; - } - - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - if ($v_string != '') { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; - } - else { - } - } - } - - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } - - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } - - // ----- Call the create fct - $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } - - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // add($p_filelist, $p_add_dir="", $p_remove_dir="") - // add($p_filelist, $p_option, $p_option_value, ...) - // Description : - // This method supports two synopsis. The first one is historical. - // This methods add the list of files in an existing archive. - // If a file with the same name already exists, it is added at the end of the - // archive, the first one is still present. - // If the archive does not exist, it is created. - // Parameters : - // $p_filelist : An array containing file or directory names, or - // a string containing one filename or one directory name, or - // a string containing a list of filenames and/or directory - // names separated by spaces. - // $p_add_dir : A path to add before the real path of the archived file, - // in order to have it memorized in the archive. - // $p_remove_dir : A path to remove from the real path of the file to archive, - // in order to have a shorter path memorized in the archive. - // When $p_add_dir and $p_remove_dir are set, $p_remove_dir - // is removed first, before $p_add_dir is added. - // Options : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_COMMENT : - // PCLZIP_OPT_ADD_COMMENT : - // PCLZIP_OPT_PREPEND_COMMENT : - // PCLZIP_CB_PRE_ADD : - // PCLZIP_CB_POST_ADD : - // Return Values : - // 0 on failure, - // The list of the added files, with a status of the add action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function add($p_filelist) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Set default values - $v_options = array(); - $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_ADD => 'optional', - PCLZIP_CB_POST_ADD => 'optional', - PCLZIP_OPT_NO_COMPRESSION => 'optional', - PCLZIP_OPT_COMMENT => 'optional', - PCLZIP_OPT_ADD_COMMENT => 'optional', - PCLZIP_OPT_PREPEND_COMMENT => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - //, PCLZIP_OPT_CRYPT => 'optional' - )); - if ($v_result != 1) { - return 0; - } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - - // ----- Get the first argument - $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; - } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - - // ----- Return - return 0; - } - } - } - - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); - - // ----- Init - $v_string_list = array(); - $v_att_list = array(); - $v_filedescr_list = array(); - $p_result_list = array(); - - // ----- Look if the $p_filelist is really an array - if (is_array($p_filelist)) { - - // ----- Look if the first element is also an array - // This will mean that this is a file description entry - if (isset($p_filelist[0]) && is_array($p_filelist[0])) { - $v_att_list = $p_filelist; - } - - // ----- The list is a list of string names - else { - $v_string_list = $p_filelist; - } - } - - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list from the string - $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); - } - - // ----- Invalid variable type for $p_filelist - else { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); - return 0; - } - - // ----- Reformat the string list - if (sizeof($v_string_list) != 0) { - foreach ($v_string_list as $v_string) { - $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; - } - } - - // ----- For each file in the list check the attributes - $v_supported_attributes - = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' - ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' - ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' - ,PCLZIP_ATT_FILE_MTIME => 'optional' - ,PCLZIP_ATT_FILE_CONTENT => 'optional' - ,PCLZIP_ATT_FILE_COMMENT => 'optional' - ); - foreach ($v_att_list as $v_entry) { - $v_result = $this->privFileDescrParseAtt($v_entry, - $v_filedescr_list[], - $v_options, - $v_supported_attributes); - if ($v_result != 1) { - return 0; - } - } - - // ----- Expand the filelist (expand directories) - $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); - if ($v_result != 1) { - return 0; - } - - // ----- Call the create fct - $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); - if ($v_result != 1) { - return 0; - } - - // ----- Return - return $p_result_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : listContent() - // Description : - // This public method, gives the list of the files and directories, with their - // properties. - // The properties of each entries in the list are (used also in other functions) : - // filename : Name of the file. For a create or add action it is the filename - // given by the user. For an extract function it is the filename - // of the extracted file. - // stored_filename : Name of the file / directory stored in the archive. - // size : Size of the stored file. - // compressed_size : Size of the file's data compressed in the archive - // (without the headers overhead) - // mtime : Last known modification date of the file (UNIX timestamp) - // comment : Comment associated with the file - // folder : true | false - // index : index of the file in the archive - // status : status of the action (depending of the action) : - // Values are : - // ok : OK ! - // filtered : the file / dir is not extracted (filtered by user) - // already_a_directory : the file can not be extracted because a - // directory with the same name already exists - // write_protected : the file can not be extracted because a file - // with the same name already exists and is - // write protected - // newer_exist : the file was not extracted because a newer file exists - // path_creation_fail : the file is not extracted because the folder - // does not exist and can not be created - // write_error : the file was not extracted because there was a - // error while writing the file - // read_error : the file was not extracted because there was a error - // while reading the file - // invalid_header : the file was not extracted because of an archive - // format error (bad file header) - // Note that each time a method can continue operating when there - // is an action error on a file, the error is only logged in the file status. - // Return Values : - // 0 on an unrecoverable failure, - // The list of the files in the archive. - // -------------------------------------------------------------------------------- - function listContent() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } - - // ----- Call the extracting fct - $p_list = array(); - if (($v_result = $this->privList($p_list)) != 1) - { - unset($p_list); - return(0); - } - - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // extract($p_path="./", $p_remove_path="") - // extract([$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method extract all the files / directories from the archive to the - // folder indicated in $p_path. - // If you want to ignore the 'root' part of path of the memorized files - // you can indicate this in the optional $p_remove_path parameter. - // By default, if a newer file with the same name already exists, the - // file is not extracted. - // - // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions - // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append - // at the end of the path value of PCLZIP_OPT_PATH. - // Parameters : - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 or a negative value on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function extract() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } - - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; - } - - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; - } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - - // ----- Get the first argument - $v_path = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; - } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - - // ----- Return - return 0; - } - } - } - - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); - - // ----- Trace - - // ----- Call the extracting fct - $p_list = array(); - $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, - $v_remove_all_path, $v_options); - if ($v_result < 1) { - unset($p_list); - return(0); - } - - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - - // -------------------------------------------------------------------------------- - // Function : - // extractByIndex($p_index, $p_path="./", $p_remove_path="") - // extractByIndex($p_index, [$p_option, $p_option_value, ...]) - // Description : - // This method supports two synopsis. The first one is historical. - // This method is doing a partial extract of the archive. - // The extracted files or folders are identified by their index in the - // archive (from 0 to n). - // Note that if the index identify a folder, only the folder entry is - // extracted, not all the files included in the archive. - // Parameters : - // $p_index : A single index (integer) or a string of indexes of files to - // extract. The form of the string is "0,4-6,8-12" with only numbers - // and '-' for range or ',' to separate ranges. No spaces or ';' - // are allowed. - // $p_path : Path where the files and directories are to be extracted - // $p_remove_path : First part ('root' part) of the memorized path - // (if any similar) to remove while extracting. - // Options : - // PCLZIP_OPT_PATH : - // PCLZIP_OPT_ADD_PATH : - // PCLZIP_OPT_REMOVE_PATH : - // PCLZIP_OPT_REMOVE_ALL_PATH : - // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and - // not as files. - // The resulting content is in a new field 'content' in the file - // structure. - // This option must be used alone (any other options are ignored). - // PCLZIP_CB_PRE_EXTRACT : - // PCLZIP_CB_POST_EXTRACT : - // Return Values : - // 0 on failure, - // The list of the extracted files, with a status of the action. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - //function extractByIndex($p_index, options...) - function extractByIndex($p_index) - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } - - // ----- Set default values - $v_options = array(); -// $v_path = "./"; - $v_path = ''; - $v_remove_path = ""; - $v_remove_all_path = false; - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Default values for option - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - - // ----- Look for arguments - if ($v_size > 1) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Remove form the options list the first argument - array_shift($v_arg_list); - $v_size--; - - // ----- Look for first arg - if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_PATH => 'optional', - PCLZIP_OPT_REMOVE_PATH => 'optional', - PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', - PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', - PCLZIP_OPT_ADD_PATH => 'optional', - PCLZIP_CB_PRE_EXTRACT => 'optional', - PCLZIP_CB_POST_EXTRACT => 'optional', - PCLZIP_OPT_SET_CHMOD => 'optional', - PCLZIP_OPT_REPLACE_NEWER => 'optional' - ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' - ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', - PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', - PCLZIP_OPT_TEMP_FILE_ON => 'optional', - PCLZIP_OPT_TEMP_FILE_OFF => 'optional' - )); - if ($v_result != 1) { - return 0; - } - - // ----- Set the arguments - if (isset($v_options[PCLZIP_OPT_PATH])) { - $v_path = $v_options[PCLZIP_OPT_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { - $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; - } - if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { - // ----- Check for '/' in last path char - if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { - $v_path .= '/'; - } - $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; - } - if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { - $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; - } - else { - } - } - - // ----- Look for 2 args - // Here we need to support the first historic synopsis of the - // method. - else { - - // ----- Get the first argument - $v_path = $v_arg_list[0]; - - // ----- Look for the optional second argument - if ($v_size == 2) { - $v_remove_path = $v_arg_list[1]; - } - else if ($v_size > 2) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); - - // ----- Return - return 0; - } - } - } - - // ----- Trace - - // ----- Trick - // Here I want to reuse extractByRule(), so I need to parse the $p_index - // with privParseOptions() - $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); - $v_options_trick = array(); - $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, - array (PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; - } - $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; - - // ----- Look for default option values - $this->privOptionDefaultThreshold($v_options); - - // ----- Call the extracting fct - if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { - return(0); - } - - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : - // delete([$p_option, $p_option_value, ...]) - // Description : - // This method removes files from the archive. - // If no parameters are given, then all the archive is emptied. - // Parameters : - // None or optional arguments. - // Options : - // PCLZIP_OPT_BY_INDEX : - // PCLZIP_OPT_BY_NAME : - // PCLZIP_OPT_BY_EREG : - // PCLZIP_OPT_BY_PREG : - // Return Values : - // 0 on failure, - // The list of the files which are still present in the archive. - // (see PclZip::listContent() for list entry format) - // -------------------------------------------------------------------------------- - function delete() - { - $v_result=1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } - - // ----- Set default values - $v_options = array(); - - // ----- Look for variable options arguments - $v_size = func_num_args(); - - // ----- Look for arguments - if ($v_size > 0) { - // ----- Get the arguments - $v_arg_list = func_get_args(); - - // ----- Parse the options - $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, - array (PCLZIP_OPT_BY_NAME => 'optional', - PCLZIP_OPT_BY_EREG => 'optional', - PCLZIP_OPT_BY_PREG => 'optional', - PCLZIP_OPT_BY_INDEX => 'optional' )); - if ($v_result != 1) { - return 0; - } - } - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Call the delete fct - $v_list = array(); - if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { - $this->privSwapBackMagicQuotes(); - unset($v_list); - return(0); - } - - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : deleteByIndex() - // Description : - // ***** Deprecated ***** - // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. - // -------------------------------------------------------------------------------- - function deleteByIndex($p_index) - { - - $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); - - // ----- Return - return $p_list; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : properties() - // Description : - // This method gives the properties of the archive. - // The properties are : - // nb : Number of files in the archive - // comment : Comment associated with the archive file - // status : not_exist, ok - // Parameters : - // None - // Return Values : - // 0 on failure, - // An array with the archive properties. - // -------------------------------------------------------------------------------- - function properties() - { - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - $this->privSwapBackMagicQuotes(); - return(0); - } - - // ----- Default properties - $v_prop = array(); - $v_prop['comment'] = ''; - $v_prop['nb'] = 0; - $v_prop['status'] = 'not_exist'; - - // ----- Look if file exists - if (@is_file($this->zipname)) - { - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - $this->privSwapBackMagicQuotes(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); - - // ----- Return - return 0; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privSwapBackMagicQuotes(); - return 0; - } - - // ----- Close the zip file - $this->privCloseFd(); - - // ----- Set the user attributes - $v_prop['comment'] = $v_central_dir['comment']; - $v_prop['nb'] = $v_central_dir['entries']; - $v_prop['status'] = 'ok'; - } - - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_prop; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : duplicate() - // Description : - // This method creates an archive by copying the content of an other one. If - // the archive already exist, it is replaced by the new one without any warning. - // Parameters : - // $p_archive : The filename of a valid archive, or - // a valid PclZip object. - // Return Values : - // 1 on success. - // 0 or a negative value on error (error code). - // -------------------------------------------------------------------------------- - function duplicate($p_archive) - { - $v_result = 1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Look if the $p_archive is a PclZip object - if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) - { - - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive->zipname); - } - - // ----- Look if the $p_archive is a string (so a filename) - else if (is_string($p_archive)) - { - - // ----- Check that $p_archive is a valid zip file - // TBC : Should also check the archive format - if (!is_file($p_archive)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); - $v_result = PCLZIP_ERR_MISSING_FILE; - } - else { - // ----- Duplicate the archive - $v_result = $this->privDuplicate($p_archive); - } - } - - // ----- Invalid variable - else - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : merge() - // Description : - // This method merge the $p_archive_to_add archive at the end of the current - // one ($this). - // If the archive ($this) does not exist, the merge becomes a duplicate. - // If the $p_archive_to_add archive does not exist, the merge is a success. - // Parameters : - // $p_archive_to_add : It can be directly the filename of a valid zip archive, - // or a PclZip object archive. - // Return Values : - // 1 on success, - // 0 or negative values on error (see below). - // -------------------------------------------------------------------------------- - function merge($p_archive_to_add) - { - $v_result = 1; - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Check archive - if (!$this->privCheckFormat()) { - return(0); - } - - // ----- Look if the $p_archive_to_add is a PclZip object - if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) - { - - // ----- Merge the archive - $v_result = $this->privMerge($p_archive_to_add); - } - - // ----- Look if the $p_archive_to_add is a string (so a filename) - else if (is_string($p_archive_to_add)) - { - - // ----- Create a temporary archive - $v_object_archive = new PclZip($p_archive_to_add); - - // ----- Merge the archive - $v_result = $this->privMerge($v_object_archive); - } - - // ----- Invalid variable - else - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); - $v_result = PCLZIP_ERR_INVALID_PARAMETER; - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - - - // -------------------------------------------------------------------------------- - // Function : errorCode() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorCode() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorCode()); - } - else { - return($this->error_code); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorName() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorName($p_with_code=false) - { - $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', - PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', - PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', - PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', - PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', - PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', - PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', - PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', - PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', - PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', - PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', - PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', - PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', - PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', - PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', - PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', - PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', - PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', - PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' - ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' - ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' - ); - - if (isset($v_name[$this->error_code])) { - $v_value = $v_name[$this->error_code]; - } - else { - $v_value = 'NoName'; - } - - if ($p_with_code) { - return($v_value.' ('.$this->error_code.')'); - } - else { - return($v_value); - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : errorInfo() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function errorInfo($p_full=false) - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - return(PclErrorString()); - } - else { - if ($p_full) { - return($this->errorName(true)." : ".$this->error_string); - } - else { - return($this->error_string." [code ".$this->error_code."]"); - } - } - } - // -------------------------------------------------------------------------------- - - -// -------------------------------------------------------------------------------- -// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** -// ***** ***** -// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** -// -------------------------------------------------------------------------------- - - - - // -------------------------------------------------------------------------------- - // Function : privCheckFormat() - // Description : - // This method check that the archive exists and is a valid zip archive. - // Several level of check exists. (futur) - // Parameters : - // $p_level : Level of check. Default 0. - // 0 : Check the first bytes (magic codes) (default value)) - // 1 : 0 + Check the central directory (futur) - // 2 : 1 + Check each file header (futur) - // Return Values : - // true on success, - // false on error, the error code is set. - // -------------------------------------------------------------------------------- - function privCheckFormat($p_level=0) - { - $v_result = true; - - // ----- Reset the file system cache - clearstatcache(); - - // ----- Reset the error handler - $this->privErrorReset(); - - // ----- Look if the file exits - if (!is_file($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); - return(false); - } - - // ----- Check that the file is readeable - if (!is_readable($this->zipname)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); - return(false); - } - - // ----- Check the magic code - // TBC - - // ----- Check the central header - // TBC - - // ----- Check each file header - // TBC - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privParseOptions() - // Description : - // This internal methods reads the variable list of arguments ($p_options_list, - // $p_size) and generate an array with the options and values ($v_result_list). - // $v_requested_options contains the options that can be present and those that - // must be present. - // $v_requested_options is an array, with the option value as key, and 'optional', - // or 'mandatory' as value. - // Parameters : - // See above. - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) - { - $v_result=1; - - // ----- Read the options - $i=0; - while ($i<$p_size) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$p_options_list[$i]])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for next option - switch ($p_options_list[$i]) { - // ----- Look for options that request a path value - case PCLZIP_OPT_PATH : - case PCLZIP_OPT_REMOVE_PATH : - case PCLZIP_OPT_ADD_PATH : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - break; - - case PCLZIP_OPT_TEMP_FILE_THRESHOLD : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } - - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } - - // ----- Check the value - $v_value = $p_options_list[$i+1]; - if ((!is_integer($v_value)) || ($v_value<0)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - return PclZip::errorCode(); - } - - // ----- Get the value (and convert it in bytes) - $v_result_list[$p_options_list[$i]] = $v_value*1048576; - $i++; - break; - - case PCLZIP_OPT_TEMP_FILE_ON : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); - return PclZip::errorCode(); - } - - $v_result_list[$p_options_list[$i]] = true; - break; - - case PCLZIP_OPT_TEMP_FILE_OFF : - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); - return PclZip::errorCode(); - } - // ----- Check for incompatible options - if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); - return PclZip::errorCode(); - } - - $v_result_list[$p_options_list[$i]] = true; - break; - - case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if ( is_string($p_options_list[$i+1]) - && ($p_options_list[$i+1] != '')) { - $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); - $i++; - } - else { - } - break; - - // ----- Look for options that request an array of string for value - case PCLZIP_OPT_BY_NAME : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an EREG or PREG expression - case PCLZIP_OPT_BY_EREG : - // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG - // to PCLZIP_OPT_BY_PREG - $p_options_list[$i] = PCLZIP_OPT_BY_PREG; - case PCLZIP_OPT_BY_PREG : - //case PCLZIP_OPT_CRYPT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that takes a string - case PCLZIP_OPT_COMMENT : - case PCLZIP_OPT_ADD_COMMENT : - case PCLZIP_OPT_PREPEND_COMMENT : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, - "Missing parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - if (is_string($p_options_list[$i+1])) { - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, - "Wrong parameter value for option '" - .PclZipUtilOptionText($p_options_list[$i]) - ."'"); - - // ----- Return - return PclZip::errorCode(); - } - $i++; - break; - - // ----- Look for options that request an array of index - case PCLZIP_OPT_BY_INDEX : - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_work_list = array(); - if (is_string($p_options_list[$i+1])) { - - // ----- Remove spaces - $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); - - // ----- Parse items - $v_work_list = explode(",", $p_options_list[$i+1]); - } - else if (is_integer($p_options_list[$i+1])) { - $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; - } - else if (is_array($p_options_list[$i+1])) { - $v_work_list = $p_options_list[$i+1]; - } - else { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Reduce the index list - // each index item in the list must be a couple with a start and - // an end value : [0,3], [5-5], [8-10], ... - // ----- Check the format of each item - $v_sort_flag=false; - $v_sort_value=0; - for ($j=0; $j= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; - $i++; - break; - - // ----- Look for options that request a call-back - case PCLZIP_CB_PRE_EXTRACT : - case PCLZIP_CB_POST_EXTRACT : - case PCLZIP_CB_PRE_ADD : - case PCLZIP_CB_POST_ADD : - /* for futur use - case PCLZIP_CB_PRE_DELETE : - case PCLZIP_CB_POST_DELETE : - case PCLZIP_CB_PRE_LIST : - case PCLZIP_CB_POST_LIST : - */ - // ----- Check the number of parameters - if (($i+1) >= $p_size) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Get the value - $v_function_name = $p_options_list[$i+1]; - - // ----- Check that the value is a valid existing function - if (!function_exists($v_function_name)) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Set the attribute - $v_result_list[$p_options_list[$i]] = $v_function_name; - $i++; - break; - - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '" - .$p_options_list[$i]."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Next options - $i++; - } - - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($v_result_list[$key])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); - - // ----- Return - return PclZip::errorCode(); - } - } - } - } - - // ----- Look for default values - if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { - - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOptionDefaultThreshold() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privOptionDefaultThreshold(&$p_options) - { - $v_result=1; - - if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { - return $v_result; - } - - // ----- Get 'memory_limit' configuration value - $v_memory_limit = ini_get('memory_limit'); - $v_memory_limit = trim($v_memory_limit); - $last = strtolower(substr($v_memory_limit, -1)); - - if($last == 'g') - //$v_memory_limit = $v_memory_limit*1024*1024*1024; - $v_memory_limit = $v_memory_limit*1073741824; - if($last == 'm') - //$v_memory_limit = $v_memory_limit*1024*1024; - $v_memory_limit = $v_memory_limit*1048576; - if($last == 'k') - $v_memory_limit = $v_memory_limit*1024; - - $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); - - - // ----- Sanity check : No threshold if value lower than 1M - if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { - unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrParseAtt() - // Description : - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) - { - $v_result=1; - - // ----- For each file in the list check the attributes - foreach ($p_file_list as $v_key => $v_value) { - - // ----- Check if the option is supported - if (!isset($v_requested_options[$v_key])) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for attribute - switch ($v_key) { - case PCLZIP_ATT_FILE_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); - - if ($p_filedescr['filename'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - break; - - case PCLZIP_ATT_FILE_NEW_SHORT_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); - - if ($p_filedescr['new_short_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; - - case PCLZIP_ATT_FILE_NEW_FULL_NAME : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); - - if ($p_filedescr['new_full_name'] == '') { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - break; - - // ----- Look for options that takes a string - case PCLZIP_ATT_FILE_COMMENT : - if (!is_string($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - $p_filedescr['comment'] = $v_value; - break; - - case PCLZIP_ATT_FILE_MTIME : - if (!is_integer($v_value)) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); - return PclZip::errorCode(); - } - - $p_filedescr['mtime'] = $v_value; - break; - - case PCLZIP_ATT_FILE_CONTENT : - $p_filedescr['content'] = $v_value; - break; - - default : - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, - "Unknown parameter '".$v_key."'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for mandatory options - if ($v_requested_options !== false) { - for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { - // ----- Look for mandatory option - if ($v_requested_options[$key] == 'mandatory') { - // ----- Look if present - if (!isset($p_file_list[$key])) { - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); - return PclZip::errorCode(); - } - } - } - } - - // end foreach - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privFileDescrExpand() - // Description : - // This method look for each item of the list to see if its a file, a folder - // or a string to be added as file. For any other type of files (link, other) - // just ignore the item. - // Then prepare the information that will be stored for that file. - // When its a folder, expand the folder with all the files that are in that - // folder (recursively). - // Parameters : - // Return Values : - // 1 on success. - // 0 on failure. - // -------------------------------------------------------------------------------- - function privFileDescrExpand(&$p_filedescr_list, &$p_options) - { - $v_result=1; - - // ----- Create a result list - $v_result_list = array(); - - // ----- Look each entry - for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); - - // ----- Add the descriptor in result list - $v_result_list[sizeof($v_result_list)] = $v_descr; - - // ----- Look for folder - if ($v_descr['type'] == 'folder') { - // ----- List of items in folder - $v_dirlist_descr = array(); - $v_dirlist_nb = 0; - if ($v_folder_handler = @opendir($v_descr['filename'])) { - while (($v_item_handler = @readdir($v_folder_handler)) !== false) { - - // ----- Skip '.' and '..' - if (($v_item_handler == '.') || ($v_item_handler == '..')) { - continue; - } - - // ----- Compose the full filename - $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; - - // ----- Look for different stored filename - // Because the name of the folder was changed, the name of the - // files/sub-folders also change - if (($v_descr['stored_filename'] != $v_descr['filename']) - && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { - if ($v_descr['stored_filename'] != '') { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; - } - else { - $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; - } - } - - $v_dirlist_nb++; - } - - @closedir($v_folder_handler); - } - else { - // TBC : unable to open folder in read mode - } - - // ----- Expand each element of the list - if ($v_dirlist_nb != 0) { - // ----- Expand - if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { - return $v_result; - } - - // ----- Concat the resulting list - $v_result_list = array_merge($v_result_list, $v_dirlist_descr); - } - else { - } - - // ----- Free local array - unset($v_dirlist_descr); - } - } - - // ----- Get the result list - $p_filedescr_list = $v_result_list; - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCreate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCreate($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the file in write mode - if (($v_result = $this->privOpenFd('wb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Add the list of files - $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); - - // ----- Close - $this->privCloseFd(); - - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAdd() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAdd($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Look if the archive exists or is empty - if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) - { - - // ----- Do a create - $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); - - // ----- Return - return $v_result; - } - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->zip_fd); - - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); - - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Create the Central Dir files header - for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - fclose($v_zip_temp_fd); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } - - // ----- Zip file comment - $v_comment = $v_central_dir['comment']; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { - $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; - } - if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; - } - - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Close - $this->privCloseFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privOpenFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privOpenFd($p_mode) - { - $v_result=1; - - // ----- Look if already open - if ($this->zip_fd != 0) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCloseFd() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privCloseFd() - { - $v_result=1; - - if ($this->zip_fd != 0) - @fclose($this->zip_fd); - $this->zip_fd = 0; - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddList() - // Description : - // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is - // different from the real path of the file. This is usefull if you want to have PclTar - // running in any directory, and memorize relative path from an other directory. - // Parameters : - // $p_list : An array containing the file or directory names to add in the tar - // $p_result_list : list of added files with their properties (specially the status field) - // $p_add_dir : Path to add in the filename path archived - // $p_remove_dir : Path to remove in the filename path archived - // Return Values : - // -------------------------------------------------------------------------------- -// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) - function privAddList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($this->zip_fd); - - // ----- Create the Central Dir files header - for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - // ----- Return - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } - - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } - - // ----- Calculate the size of the central header - $v_size = @ftell($this->zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); - - // ----- Return - return $v_result; - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileList() - // Description : - // Parameters : - // $p_filedescr_list : An array containing the file description - // or directory names to add in the zip - // $p_result_list : list of added files with their properties (specially the status field) - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) - { - $v_result=1; - $v_header = array(); - - // ----- Recuperate the current number of elt in list - $v_nb = sizeof($p_result_list); - - // ----- Loop on the files - for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, - $p_options); - if ($v_result != 1) { - return $v_result; - } - - // ----- Store the file infos - $p_result_list[$v_nb++] = $v_header; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=1; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - // TBC : Already done in the fileAtt check ... ? - if ($p_filename == "") { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for a stored different filename - /* TBC : Removed - if (isset($p_filedescr['stored_filename'])) { - $v_stored_filename = $p_filedescr['stored_filename']; - } - else { - $v_stored_filename = $p_filedescr['stored_filename']; - } - */ - - // ----- Set the file properties - clearstatcache(); - $p_header['version'] = 20; - $p_header['version_extracted'] = 10; - $p_header['flag'] = 0; - $p_header['compression'] = 0; - $p_header['crc'] = 0; - $p_header['compressed_size'] = 0; - $p_header['filename_len'] = strlen($p_filename); - $p_header['extra_len'] = 0; - $p_header['disk'] = 0; - $p_header['internal'] = 0; - $p_header['offset'] = 0; - $p_header['filename'] = $p_filename; -// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; - $p_header['stored_filename'] = $p_filedescr['stored_filename']; - $p_header['extra'] = ''; - $p_header['status'] = 'ok'; - $p_header['index'] = -1; - - // ----- Look for regular file - if ($p_filedescr['type']=='file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = filesize($p_filename); - } - - // ----- Look for regular folder - else if ($p_filedescr['type']=='folder') { - $p_header['external'] = 0x00000010; - $p_header['mtime'] = filemtime($p_filename); - $p_header['size'] = filesize($p_filename); - } - - // ----- Look for virtual file - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['external'] = 0x00000000; - $p_header['size'] = strlen($p_filedescr['content']); - } - - - // ----- Look for filetime - if (isset($p_filedescr['mtime'])) { - $p_header['mtime'] = $p_filedescr['mtime']; - } - else if ($p_filedescr['type'] == 'virtual_file') { - $p_header['mtime'] = time(); - } - else { - $p_header['mtime'] = filemtime($p_filename); - } - - // ------ Look for file comment - if (isset($p_filedescr['comment'])) { - $p_header['comment_len'] = strlen($p_filedescr['comment']); - $p_header['comment'] = $p_filedescr['comment']; - } - else { - $p_header['comment_len'] = 0; - $p_header['comment'] = ''; - } - - // ----- Look for pre-add callback - if (isset($p_options[PCLZIP_CB_PRE_ADD])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_header['status'] = "skipped"; - $v_result = 1; - } - - // ----- Update the informations - // Only some fields can be modified - if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { - $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); - } - } - - // ----- Look for empty stored filename - if ($p_header['stored_filename'] == "") { - $p_header['status'] = "filtered"; - } - - // ----- Check the path length - if (strlen($p_header['stored_filename']) > 0xFF) { - $p_header['status'] = 'filename_too_long'; - } - - // ----- Look if no error, or file not skipped - if ($p_header['status'] == 'ok') { - - // ----- Look for a file - if ($p_filedescr['type'] == 'file') { - // ----- Look for using temporary file to zip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { - $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; - } - } - - // ----- Use "in memory" zip algo - else { - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); - } - - // ----- Read the file content - $v_content = @fread($v_file, $p_header['size']); - - // ----- Close the file - @fclose($v_file); - - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); - - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; - } - - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); - - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } - - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; - } - - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); - - } - - } - - // ----- Look for a virtual file (a file from string) - else if ($p_filedescr['type'] == 'virtual_file') { - - $v_content = $p_filedescr['content']; - - // ----- Calculate the CRC - $p_header['crc'] = @crc32($v_content); - - // ----- Look for no compression - if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { - // ----- Set header parameters - $p_header['compressed_size'] = $p_header['size']; - $p_header['compression'] = 0; - } - - // ----- Look for normal compression - else { - // ----- Compress the content - $v_content = @gzdeflate($v_content); - - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content); - $p_header['compression'] = 8; - } - - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; - } - - // ----- Write the compressed (or not) content - @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); - } - - // ----- Look for a directory - else if ($p_filedescr['type'] == 'folder') { - // ----- Look for directory last '/' - if (@substr($p_header['stored_filename'], -1) != '/') { - $p_header['stored_filename'] .= '/'; - } - - // ----- Set the file properties - $p_header['size'] = 0; - //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked - $p_header['external'] = 0x00000010; // Value for a folder : to be checked - - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) - { - return $v_result; - } - } - } - - // ----- Look for post-add callback - if (isset($p_options[PCLZIP_CB_POST_ADD])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); - if ($v_result == 0) { - // ----- Ignored - $v_result = 1; - } - - // ----- Update the informations - // Nothing can be modified - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privAddFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) - { - $v_result=PCLZIP_ERR_NO_ERROR; - - // ----- Working variable - $p_filename = $p_filedescr['filename']; - - - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return PclZip::errorCode(); - } - - // ----- Creates a compressed temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } - - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = filesize($p_filename); - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @gzputs($v_file_compressed, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Close the file - @fclose($v_file); - @gzclose($v_file_compressed); - - // ----- Check the minimum file size - if (filesize($v_gzip_temp_name) < 18) { - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); - return PclZip::errorCode(); - } - - // ----- Extract the compressed attributes - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } - - // ----- Read the gzip file header - $v_binary_data = @fread($v_file_compressed, 10); - $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); - - // ----- Check some parameters - $v_data_header['os'] = bin2hex($v_data_header['os']); - - // ----- Read the gzip file footer - @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); - $v_binary_data = @fread($v_file_compressed, 8); - $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); - - // ----- Set the attributes - $p_header['compression'] = ord($v_data_header['cm']); - //$p_header['mtime'] = $v_data_header['mtime']; - $p_header['crc'] = $v_data_footer['crc']; - $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; - - // ----- Close the file - @fclose($v_file_compressed); - - // ----- Call the header generation - if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { - return $v_result; - } - - // ----- Add the compressed data - if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) - { - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } - - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - fseek($v_file_compressed, 10); - $v_size = $p_header['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_file_compressed, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Close the file - @fclose($v_file_compressed); - - // ----- Unlink the temporary file - @unlink($v_gzip_temp_name); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCalculateStoredFilename() - // Description : - // Based on file descriptor properties and global options, this method - // calculate the filename that will be stored in the archive. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privCalculateStoredFilename(&$p_filedescr, &$p_options) - { - $v_result=1; - - // ----- Working variables - $p_filename = $p_filedescr['filename']; - if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { - $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; - } - else { - $p_add_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { - $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; - } - else { - $p_remove_dir = ''; - } - if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { - $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; - } - else { - $p_remove_all_dir = 0; - } - - - // ----- Look for full name change - if (isset($p_filedescr['new_full_name'])) { - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); - } - - // ----- Look for path and/or short name change - else { - - // ----- Look for short name change - // Its when we cahnge just the filename but not the path - if (isset($p_filedescr['new_short_name'])) { - $v_path_info = pathinfo($p_filename); - $v_dir = ''; - if ($v_path_info['dirname'] != '') { - $v_dir = $v_path_info['dirname'].'/'; - } - $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; - } - else { - // ----- Calculate the stored filename - $v_stored_filename = $p_filename; - } - - // ----- Look for all path to remove - if ($p_remove_all_dir) { - $v_stored_filename = basename($p_filename); - } - // ----- Look for partial path remove - else if ($p_remove_dir != "") { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= "/"; - - if ( (substr($p_filename, 0, 2) == "./") - || (substr($p_remove_dir, 0, 2) == "./")) { - - if ( (substr($p_filename, 0, 2) == "./") - && (substr($p_remove_dir, 0, 2) != "./")) { - $p_remove_dir = "./".$p_remove_dir; - } - if ( (substr($p_filename, 0, 2) != "./") - && (substr($p_remove_dir, 0, 2) == "./")) { - $p_remove_dir = substr($p_remove_dir, 2); - } - } - - $v_compare = PclZipUtilPathInclusion($p_remove_dir, - $v_stored_filename); - if ($v_compare > 0) { - if ($v_compare == 2) { - $v_stored_filename = ""; - } - else { - $v_stored_filename = substr($v_stored_filename, - strlen($p_remove_dir)); - } - } - } - - // ----- Remove drive letter if any - $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); - - // ----- Look for path to add - if ($p_add_dir != "") { - if (substr($p_add_dir, -1) == "/") - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir."/".$v_stored_filename; - } - } - - // ----- Filename (reduce the path of stored name) - $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); - $p_filedescr['stored_filename'] = $v_stored_filename; - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteFileHeader(&$p_header) - { - $v_result=1; - - // ----- Store the offset position of the file - $p_header['offset'] = ftell($this->zip_fd); - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - // ----- Packed data - $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, - $p_header['version_extracted'], $p_header['flag'], - $p_header['compression'], $v_mtime, $v_mdate, - $p_header['crc'], $p_header['compressed_size'], - $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len']); - - // ----- Write the first 148 bytes of the header in the archive - fputs($this->zip_fd, $v_binary_data, 30); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralFileHeader(&$p_header) - { - $v_result=1; - - // TBC - //for(reset($p_header); $key = key($p_header); next($p_header)) { - //} - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - - // ----- Packed data - $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, - $p_header['version'], $p_header['version_extracted'], - $p_header['flag'], $p_header['compression'], - $v_mtime, $v_mdate, $p_header['crc'], - $p_header['compressed_size'], $p_header['size'], - strlen($p_header['stored_filename']), - $p_header['extra_len'], $p_header['comment_len'], - $p_header['disk'], $p_header['internal'], - $p_header['external'], $p_header['offset']); - - // ----- Write the 42 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 46); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); - } - if ($p_header['comment_len'] != 0) - { - fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privWriteCentralHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) - { - $v_result=1; - - // ----- Packed data - $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, - $p_nb_entries, $p_size, - $p_offset, strlen($p_comment)); - - // ----- Write the 22 bytes of the header in the zip file - fputs($this->zip_fd, $v_binary_data, 22); - - // ----- Write the variable fields - if (strlen($p_comment) != 0) - { - fputs($this->zip_fd, $p_comment, strlen($p_comment)); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privList() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privList(&$p_list) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Open the zip file - if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) - { - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Go to beginning of Central Dir - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_central_dir['offset'])) - { - $this->privSwapBackMagicQuotes(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read each entry - for ($i=0; $i<$v_central_dir['entries']; $i++) - { - // ----- Read the file header - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } - $v_header['index'] = $i; - - // ----- Get the only interesting attributes - $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); - unset($v_header); - } - - // ----- Close the zip file - $this->privCloseFd(); - - // ----- Magic quotes trick - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privConvertHeader2FileInfo() - // Description : - // This function takes the file informations from the central directory - // entries and extract the interesting parameters that will be given back. - // The resulting file infos are set in the array $p_info - // $p_info['filename'] : Filename with full path. Given by user (add), - // extracted in the filesystem (extract). - // $p_info['stored_filename'] : Stored filename in the archive. - // $p_info['size'] = Size of the file. - // $p_info['compressed_size'] = Compressed size of the file. - // $p_info['mtime'] = Last modification date of the file. - // $p_info['comment'] = Comment associated with the file. - // $p_info['folder'] = true/false : indicates if the entry is a folder or not. - // $p_info['status'] = status of the action on the file. - // $p_info['crc'] = CRC of the file content. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privConvertHeader2FileInfo($p_header, &$p_info) - { - $v_result=1; - - // ----- Get the interesting attributes - $v_temp_path = PclZipUtilPathReduction($p_header['filename']); - $p_info['filename'] = $v_temp_path; - $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); - $p_info['stored_filename'] = $v_temp_path; - $p_info['size'] = $p_header['size']; - $p_info['compressed_size'] = $p_header['compressed_size']; - $p_info['mtime'] = $p_header['mtime']; - $p_info['comment'] = $p_header['comment']; - $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); - $p_info['index'] = $p_header['index']; - $p_info['status'] = $p_header['status']; - $p_info['crc'] = $p_header['crc']; - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractByRule() - // Description : - // Extract a file or directory depending of rules (by index, by name, ...) - // Parameters : - // $p_file_list : An array where will be placed the properties of each - // extracted file - // $p_path : Path to add while writing the extracted files - // $p_remove_path : Path to remove (from the file memorized path) while writing the - // extracted files. If the path does not match the file path, - // the file is extracted with its memorized path. - // $p_remove_path does not apply to 'list' mode. - // $p_path and $p_remove_path are commulative. - // Return Values : - // 1 on success,0 or less on error (see error code list) - // -------------------------------------------------------------------------------- - function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Magic quotes trick - $this->privDisableMagicQuotes(); - - // ----- Check the path - if ( ($p_path == "") - || ( (substr($p_path, 0, 1) != "/") - && (substr($p_path, 0, 3) != "../") - && (substr($p_path,1,2)!=":/"))) - $p_path = "./".$p_path; - - // ----- Reduce the path last (and duplicated) '/' - if (($p_path != "./") && ($p_path != "/")) - { - // ----- Look for the path end '/' - while (substr($p_path, -1) == "/") - { - $p_path = substr($p_path, 0, strlen($p_path)-1); - } - } - - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) - { - $p_remove_path .= '/'; - } - $p_remove_path_size = strlen($p_remove_path); - - // ----- Open the zip file - if (($v_result = $this->privOpenFd('rb')) != 1) - { - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - return $v_result; - } - - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - - // ----- Read each entry - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { - - // ----- Read next Central dir entry - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - return $v_result; - } - - // ----- Store the index - $v_header['index'] = $i; - - // ----- Store the file position - $v_pos_entry = ftell($this->zip_fd); - - // ----- Look for the specific extract rules - $v_extract = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_extract = true; - } - } - // ----- Look for a filename - elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_extract = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_extract = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - - // ----- Look for no rule, which means extract all the archive - else { - $v_extract = true; - } - - // ----- Check compression method - if ( ($v_extract) - && ( ($v_header['compression'] != 8) - && ($v_header['compression'] != 0))) { - $v_header['status'] = 'unsupported_compression'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, - "Filename '".$v_header['stored_filename']."' is " - ."compressed by an unsupported compression " - ."method (".$v_header['compression'].") "); - - return PclZip::errorCode(); - } - } - - // ----- Check encrypted files - if (($v_extract) && (($v_header['flag'] & 1) == 1)) { - $v_header['status'] = 'unsupported_encryption'; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - $this->privSwapBackMagicQuotes(); - - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, - "Unsupported encryption for " - ." filename '".$v_header['stored_filename'] - ."'"); - - return PclZip::errorCode(); - } - } - - // ----- Look for real extraction - if (($v_extract) && ($v_header['status'] != 'ok')) { - $v_result = $this->privConvertHeader2FileInfo($v_header, - $p_file_list[$v_nb_extracted++]); - if ($v_result != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - $v_extract = false; - } - - // ----- Look for real extraction - if ($v_extract) - { - - // ----- Go to the file position - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_header['offset'])) - { - // ----- Close the zip file - $this->privCloseFd(); - - $this->privSwapBackMagicQuotes(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Look for extraction as string - if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { - - $v_string = ''; - - // ----- Extracting the file - $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } - - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - return $v_result; - } - - // ----- Set the file content - $p_file_list[$v_nb_extracted]['content'] = $v_string; - - // ----- Next extracted file - $v_nb_extracted++; - - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - // ----- Look for extraction in standard output - elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) - && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { - // ----- Extracting the file in standard output - $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } - - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result; - } - - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - // ----- Look for normal extraction - else { - // ----- Extracting the file - $v_result1 = $this->privExtractFile($v_header, - $p_path, $p_remove_path, - $p_remove_all_path, - $p_options); - if ($v_result1 < 1) { - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - return $v_result1; - } - - // ----- Get the only interesting attributes - if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - return $v_result; - } - - // ----- Look for user callback abort - if ($v_result1 == 2) { - break; - } - } - } - } - - // ----- Close the zip file - $this->privCloseFd(); - $this->privSwapBackMagicQuotes(); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFile() - // Description : - // Parameters : - // Return Values : - // - // 1 : ... ? - // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback - // -------------------------------------------------------------------------------- - function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } - - - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC - } - - // ----- Look for all path to remove - if ($p_remove_all_path == true) { - // ----- Look for folder entry that not need to be extracted - if (($p_entry['external']&0x00000010)==0x00000010) { - - $p_entry['status'] = "filtered"; - - return $v_result; - } - - // ----- Get the basename of the path - $p_entry['filename'] = basename($p_entry['filename']); - } - - // ----- Look for path to remove - else if ($p_remove_path != "") - { - if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) - { - - // ----- Change the file status - $p_entry['status'] = "filtered"; - - // ----- Return - return $v_result; - } - - $p_remove_path_size = strlen($p_remove_path); - if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) - { - - // ----- Remove the path - $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); - - } - } - - // ----- Add the path - if ($p_path != '') { - $p_entry['filename'] = $p_path."/".$p_entry['filename']; - } - - // ----- Check a base_dir_restriction - if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { - $v_inclusion - = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], - $p_entry['filename']); - if ($v_inclusion == 0) { - - PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, - "Filename '".$p_entry['filename']."' is " - ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); - - return PclZip::errorCode(); - } - } - - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Look for specific actions while the file exist - if (file_exists($p_entry['filename'])) - { - - // ----- Look if file is a directory - if (is_dir($p_entry['filename'])) - { - - // ----- Change the file status - $p_entry['status'] = "already_a_directory"; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, - "Filename '".$p_entry['filename']."' is " - ."already used by an existing directory"); - - return PclZip::errorCode(); - } - } - // ----- Look if file is write protected - else if (!is_writeable($p_entry['filename'])) - { - - // ----- Change the file status - $p_entry['status'] = "write_protected"; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Filename '".$p_entry['filename']."' exists " - ."and is write protected"); - - return PclZip::errorCode(); - } - } - - // ----- Look if the extracted file is older - else if (filemtime($p_entry['filename']) > $p_entry['mtime']) - { - // ----- Change the file status - if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) - && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { - } - else { - $p_entry['status'] = "newer_exist"; - - // ----- Look for PCLZIP_OPT_STOP_ON_ERROR - // For historical reason first PclZip implementation does not stop - // when this kind of error occurs. - if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) - && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { - - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, - "Newer version of '".$p_entry['filename']."' exists " - ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); - - return PclZip::errorCode(); - } - } - } - else { - } - } - - // ----- Check the directory availability and create it if necessary - else { - if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) - $v_dir_to_check = $p_entry['filename']; - else if (!strstr($p_entry['filename'], "/")) - $v_dir_to_check = ""; - else - $v_dir_to_check = dirname($p_entry['filename']); - - if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { - - // ----- Change the file status - $p_entry['status'] = "path_creation_fail"; - - // ----- Return - //return $v_result; - $v_result = 1; - } - } - } - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) - { - // ----- Look for not compressed file - if ($p_entry['compression'] == 0) { - - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) - { - - // ----- Change the file status - $p_entry['status'] = "write_error"; - - // ----- Return - return $v_result; - } - - - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - /* Try to speed up the code - $v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_binary_data, $v_read_size); - */ - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Closing the destination file - fclose($v_dest_file); - - // ----- Change the file mtime - touch($p_entry['filename'], $p_entry['mtime']); - - - } - else { - // ----- TBC - // Need to be finished - if (($p_entry['flag'] & 1) == 1) { - PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); - return PclZip::errorCode(); - } - - - // ----- Look for using temporary file to unzip - if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) - && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) - || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) - && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { - $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); - if ($v_result < PCLZIP_ERR_NO_ERROR) { - return $v_result; - } - } - - // ----- Look for extract in memory - else { - - - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - - // ----- Decompress the file - $v_file_content = @gzinflate($v_buffer); - unset($v_buffer); - if ($v_file_content === FALSE) { - - // ----- Change the file status - // TBC - $p_entry['status'] = "error"; - - return $v_result; - } - - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - - // ----- Change the file status - $p_entry['status'] = "write_error"; - - return $v_result; - } - - // ----- Write the uncompressed data - @fwrite($v_dest_file, $v_file_content, $p_entry['size']); - unset($v_file_content); - - // ----- Closing the destination file - @fclose($v_dest_file); - - } - - // ----- Change the file mtime - @touch($p_entry['filename'], $p_entry['mtime']); - } - - // ----- Look for chmod option - if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { - - // ----- Change the mode of the file - @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); - } - - } - } - - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } - - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileUsingTempFile() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileUsingTempFile(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Creates a temporary file - $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; - if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { - fclose($v_file); - PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); - return PclZip::errorCode(); - } - - - // ----- Write gz file format header - $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); - @fwrite($v_dest_file, $v_binary_data, 10); - - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Write gz file format footer - $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); - @fwrite($v_dest_file, $v_binary_data, 8); - - // ----- Close the temporary file - @fclose($v_dest_file); - - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - $p_entry['status'] = "write_error"; - return $v_result; - } - - // ----- Open the temporary gz file - if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { - @fclose($v_dest_file); - $p_entry['status'] = "read_error"; - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); - return PclZip::errorCode(); - } - - - // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['size']; - while ($v_size != 0) { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($v_src_file, $v_read_size); - //$v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - @fclose($v_dest_file); - @gzclose($v_src_file); - - // ----- Delete the temporary file - @unlink($v_gzip_temp_name); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileInOutput() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileInOutput(&$p_entry, &$p_options) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->privReadFileHeader($v_header)) != 1) { - return $v_result; - } - - - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC - } - - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - - // ----- Trace - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - if ($p_entry['compressed_size'] == $p_entry['size']) { - - // ----- Read the file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - - // ----- Send the file to the output - echo $v_buffer; - unset($v_buffer); - } - else { - - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); - - // ----- Decompress the file - $v_file_content = gzinflate($v_buffer); - unset($v_buffer); - - // ----- Send the file to the output - echo $v_file_content; - unset($v_file_content); - } - } - } - - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } - - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } - - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privExtractFileAsString() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) - { - $v_result=1; - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->privReadFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } - - - // ----- Check that the file header is coherent with $p_entry info - if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { - // TBC - } - - // ----- Look for pre-extract callback - if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Look for abort result - if ($v_result == 2) { - // ----- This status is internal and will be changed in 'skipped' - $p_entry['status'] = "aborted"; - $v_result = PCLZIP_ERR_USER_ABORTED; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) { - // ----- Look for not compressed file - // if ($p_entry['compressed_size'] == $p_entry['size']) - if ($p_entry['compression'] == 0) { - - // ----- Reading the file - $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); - } - else { - - // ----- Reading the file - $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); - - // ----- Decompress the file - if (($p_string = @gzinflate($v_data)) === FALSE) { - // TBC - } - } - - // ----- Trace - } - else { - // TBC : error : can not extract a folder in a string - } - - } - - // ----- Change abort status - if ($p_entry['status'] == "aborted") { - $p_entry['status'] = "skipped"; - } - - // ----- Look for post-extract callback - elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { - - // ----- Generate a local information - $v_local_header = array(); - $this->privConvertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Swap the content to header - $v_local_header['content'] = $p_string; - $p_string = ''; - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. -// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); - $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); - - // ----- Swap back the content to header - $p_string = $v_local_header['content']; - unset($v_local_header['content']); - - // ----- Look for abort result - if ($v_result == 2) { - $v_result = PCLZIP_ERR_USER_ABORTED; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x04034b50) - { - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 26); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 26) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Extract the values - $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); - - // ----- Get filename - $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); - - // ----- Get extra_fields - if ($v_data['extra_len'] != 0) { - $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); - } - else { - $p_header['extra'] = ''; - } - - // ----- Extract properties - $p_header['version_extracted'] = $v_data['version']; - $p_header['compression'] = $v_data['compression']; - $p_header['size'] = $v_data['size']; - $p_header['compressed_size'] = $v_data['compressed_size']; - $p_header['crc'] = $v_data['crc']; - $p_header['flag'] = $v_data['flag']; - $p_header['filename_len'] = $v_data['filename_len']; - - // ----- Recuperate date in UNIX format - $p_header['mdate'] = $v_data['mdate']; - $p_header['mtime'] = $v_data['mtime']; - if ($p_header['mdate'] && $p_header['mtime']) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - - } - else - { - $p_header['mtime'] = time(); - } - - // TBC - //for(reset($v_data); $key = key($v_data); next($v_data)) { - //} - - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; - - // ----- Set the status field - $p_header['status'] = "ok"; - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadCentralFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x02014b50) - { - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->zip_fd, 42); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 42) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Extract the values - $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - - // ----- Get filename - if ($p_header['filename_len'] != 0) - $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); - else - $p_header['filename'] = ''; - - // ----- Get extra - if ($p_header['extra_len'] != 0) - $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); - else - $p_header['extra'] = ''; - - // ----- Get comment - if ($p_header['comment_len'] != 0) - $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); - else - $p_header['comment'] = ''; - - // ----- Extract properties - - // ----- Recuperate date in UNIX format - //if ($p_header['mdate'] && $p_header['mtime']) - // TBC : bug : this was ignoring time with 0/0/0 - if (1) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - - } - else - { - $p_header['mtime'] = time(); - } - - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; - - // ----- Set default status to ok - $p_header['status'] = 'ok'; - - // ----- Look if it is a directory - if (substr($p_header['filename'], -1) == '/') { - //$p_header['external'] = 0x41FF0010; - $p_header['external'] = 0x00000010; - } - - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privCheckFileHeaders() - // Description : - // Parameters : - // Return Values : - // 1 on success, - // 0 on error; - // -------------------------------------------------------------------------------- - function privCheckFileHeaders(&$p_local_header, &$p_central_header) - { - $v_result=1; - - // ----- Check the static values - // TBC - if ($p_local_header['filename'] != $p_central_header['filename']) { - } - if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { - } - if ($p_local_header['flag'] != $p_central_header['flag']) { - } - if ($p_local_header['compression'] != $p_central_header['compression']) { - } - if ($p_local_header['mtime'] != $p_central_header['mtime']) { - } - if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { - } - - // ----- Look for flag bit 3 - if (($p_local_header['flag'] & 8) == 8) { - $p_local_header['size'] = $p_central_header['size']; - $p_local_header['compressed_size'] = $p_central_header['compressed_size']; - $p_local_header['crc'] = $p_central_header['crc']; - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privReadEndCentralDir() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privReadEndCentralDir(&$p_central_dir) - { - $v_result=1; - - // ----- Go to the end of the zip file - $v_size = filesize($this->zipname); - @fseek($this->zip_fd, $v_size); - if (@ftell($this->zip_fd) != $v_size) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- First try : look if this is an archive with no commentaries (most of the time) - // in this case the end of central dir is at 22 bytes of the file end - $v_found = 0; - if ($v_size > 26) { - @fseek($this->zip_fd, $v_size-22); - if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read for bytes - $v_binary_data = @fread($this->zip_fd, 4); - $v_data = @unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] == 0x06054b50) { - $v_found = 1; - } - - $v_pos = ftell($this->zip_fd); - } - - // ----- Go back to the maximum possible size of the Central Dir End Record - if (!$v_found) { - $v_maximum_size = 65557; // 0xFFFF + 22; - if ($v_maximum_size > $v_size) - $v_maximum_size = $v_size; - @fseek($this->zip_fd, $v_size-$v_maximum_size); - if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read byte per byte in order to find the signature - $v_pos = ftell($this->zip_fd); - $v_bytes = 0x00000000; - while ($v_pos < $v_size) - { - // ----- Read a byte - $v_byte = @fread($this->zip_fd, 1); - - // ----- Add the byte - //$v_bytes = ($v_bytes << 8) | Ord($v_byte); - // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number - // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. - $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); - - // ----- Compare the bytes - if ($v_bytes == 0x504b0506) - { - $v_pos++; - break; - } - - $v_pos++; - } - - // ----- Look if not found end of central dir - if ($v_pos == $v_size) - { - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); - - // ----- Return - return PclZip::errorCode(); - } - } - - // ----- Read the first 18 bytes of the header - $v_binary_data = fread($this->zip_fd, 18); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 18) - { - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Extract the values - $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); - - // ----- Check the global size - if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - - // ----- Removed in release 2.2 see readme file - // The check of the file size is a little too strict. - // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. - // While decrypted, zip has training 0 bytes - if (0) { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, - 'The central dir is not at the end of the archive.' - .' Some trailing bytes exists after the archive.'); - - // ----- Return - return PclZip::errorCode(); - } - } - - // ----- Get comment - if ($v_data['comment_size'] != 0) { - $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); - } - else - $p_central_dir['comment'] = ''; - - $p_central_dir['entries'] = $v_data['entries']; - $p_central_dir['disk_entries'] = $v_data['disk_entries']; - $p_central_dir['offset'] = $v_data['offset']; - $p_central_dir['size'] = $v_data['size']; - $p_central_dir['disk'] = $v_data['disk']; - $p_central_dir['disk_start'] = $v_data['disk_start']; - - // TBC - //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { - //} - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDeleteByRule() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDeleteByRule(&$p_result_list, &$p_options) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->zip_fd); - - // ----- Scan all the files - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - @rewind($this->zip_fd); - if (@fseek($this->zip_fd, $v_pos_entry)) - { - // ----- Close the zip file - $this->privCloseFd(); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read each entry - $v_header_list = array(); - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) - { - - // ----- Read the file header - $v_header_list[$v_nb_extracted] = array(); - if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->privCloseFd(); - - return $v_result; - } - - - // ----- Store the index - $v_header_list[$v_nb_extracted]['index'] = $i; - - // ----- Look for the specific extract rules - $v_found = false; - - // ----- Look for extract by name rule - if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) - && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) - && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ - && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { - $v_found = true; - } - } - // ----- Look for a filename - elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { - $v_found = true; - } - } - } - - // ----- Look for extract by ereg rule - // ereg() is deprecated with PHP 5.3 - /* - else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) - && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { - - if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - */ - - // ----- Look for extract by preg rule - else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) - && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { - - if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) - && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { - $v_found = true; - } - if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - else { - $v_found = true; - } - - // ----- Look for deletion - if ($v_found) - { - unset($v_header_list[$v_nb_extracted]); - } - else - { - $v_nb_extracted++; - } - } - - // ----- Look if something need to be deleted - if ($v_nb_extracted > 0) { - - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; - - // ----- Creates a temporary zip archive - $v_temp_zip = new PclZip($v_zip_temp_name); - - // ----- Open the temporary zip file in write mode - if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { - $this->privCloseFd(); - - // ----- Return - return $v_result; - } - - // ----- Look which file need to be kept - for ($i=0; $izip_fd); - if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Read the file header - $v_local_header = array(); - if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - - // ----- Check that local file header is same as central file header - if ($this->privCheckFileHeaders($v_local_header, - $v_header_list[$i]) != 1) { - // TBC - } - unset($v_local_header); - - // ----- Write the file header - if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - - // ----- Read/write the data block - if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { - // ----- Close the zip file - $this->privCloseFd(); - $v_temp_zip->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($v_temp_zip->zip_fd); - - // ----- Re-Create the Central Dir files header - for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - - // ----- Transform the header to a 'usable' info - $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } - - - // ----- Zip file comment - $v_comment = ''; - if (isset($p_options[PCLZIP_OPT_COMMENT])) { - $v_comment = $p_options[PCLZIP_OPT_COMMENT]; - } - - // ----- Calculate the size of the central header - $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { - // ----- Reset the file list - unset($v_header_list); - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - - // ----- Close - $v_temp_zip->privCloseFd(); - $this->privCloseFd(); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); - - // ----- Destroy the temporary archive - unset($v_temp_zip); - } - - // ----- Remove every files : reset the file - else if ($v_central_dir['entries'] != 0) { - $this->privCloseFd(); - - if (($v_result = $this->privOpenFd('wb')) != 1) { - return $v_result; - } - - if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { - return $v_result; - } - - $this->privCloseFd(); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDirCheck() - // Description : - // Check if a directory exists, if not it creates it and all the parents directory - // which may be useful. - // Parameters : - // $p_dir : Directory path to check. - // Return Values : - // 1 : OK - // -1 : Unable to create directory - // -------------------------------------------------------------------------------- - function privDirCheck($p_dir, $p_is_dir=false) - { - $v_result = 1; - - - // ----- Remove the final '/' - if (($p_is_dir) && (substr($p_dir, -1)=='/')) - { - $p_dir = substr($p_dir, 0, strlen($p_dir)-1); - } - - // ----- Check the directory availability - if ((is_dir($p_dir)) || ($p_dir == "")) - { - return 1; - } - - // ----- Extract parent directory - $p_parent_dir = dirname($p_dir); - - // ----- Just a check - if ($p_parent_dir != $p_dir) - { - // ----- Look for parent directory - if ($p_parent_dir != "") - { - if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) - { - return $v_result; - } - } - } - - // ----- Create the directory - if (!@mkdir($p_dir, 0777)) - { - // ----- Error log - PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privMerge() - // Description : - // If $p_archive_to_add does not exist, the function exit with a success result. - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privMerge(&$p_archive_to_add) - { - $v_result=1; - - // ----- Look if the archive_to_add exists - if (!is_file($p_archive_to_add->zipname)) - { - - // ----- Nothing to merge, so merge is a success - $v_result = 1; - - // ----- Return - return $v_result; - } - - // ----- Look if the archive exists - if (!is_file($this->zipname)) - { - - // ----- Do a duplicate - $v_result = $this->privDuplicate($p_archive_to_add->zipname); - - // ----- Return - return $v_result; - } - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('rb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) - { - $this->privCloseFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->zip_fd); - - // ----- Open the archive_to_add file - if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) - { - $this->privCloseFd(); - - // ----- Return - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir_to_add = array(); - if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - - return $v_result; - } - - // ----- Go to beginning of File - @rewind($p_archive_to_add->zip_fd); - - // ----- Creates a temporay file - $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Copy the files from the archive_to_add into the temporary file - $v_size = $v_central_dir_to_add['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($v_zip_temp_fd); - - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Copy the block of file headers from the archive_to_add - $v_size = $v_central_dir_to_add['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Merge the file comments - $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; - - // ----- Calculate the size of the (new) central header - $v_size = @ftell($v_zip_temp_fd)-$v_offset; - - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive fd - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Create the central dir footer - if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) - { - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - @fclose($v_zip_temp_fd); - $this->zip_fd = null; - - // ----- Reset the file list - unset($v_header_list); - - // ----- Return - return $v_result; - } - - // ----- Swap back the file descriptor - $v_swap = $this->zip_fd; - $this->zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Close - $this->privCloseFd(); - $p_archive_to_add->privCloseFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->zipname); - PclZipUtilRename($v_zip_temp_name, $this->zipname); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDuplicate() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDuplicate($p_archive_filename) - { - $v_result=1; - - // ----- Look if the $p_archive_filename exists - if (!is_file($p_archive_filename)) - { - - // ----- Nothing to duplicate, so duplicate is a success. - $v_result = 1; - - // ----- Return - return $v_result; - } - - // ----- Open the zip file - if (($v_result=$this->privOpenFd('wb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) - { - $this->privCloseFd(); - - PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); - - // ----- Return - return PclZip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the central dir - $v_size = filesize($p_archive_filename); - while ($v_size != 0) - { - $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Close - $this->privCloseFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorLog() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorLog($p_error_code=0, $p_error_string='') - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclError($p_error_code, $p_error_string); - } - else { - $this->error_code = $p_error_code; - $this->error_string = $p_error_string; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privErrorReset() - // Description : - // Parameters : - // -------------------------------------------------------------------------------- - function privErrorReset() - { - if (PCLZIP_ERROR_EXTERNAL == 1) { - PclErrorReset(); - } - else { - $this->error_code = 0; - $this->error_string = ''; - } - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privDisableMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privDisableMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; - } - - // ----- Look if already done - if ($this->magic_quotes_status != -1) { - return $v_result; - } - - // ----- Get and memorize the magic_quote value - $this->magic_quotes_status = @get_magic_quotes_runtime(); - - // ----- Disable magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime(0); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : privSwapBackMagicQuotes() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function privSwapBackMagicQuotes() - { - $v_result=1; - - // ----- Look if function exists - if ( (!function_exists("get_magic_quotes_runtime")) - || (!function_exists("set_magic_quotes_runtime"))) { - return $v_result; - } - - // ----- Look if something to do - if ($this->magic_quotes_status != -1) { - return $v_result; - } - - // ----- Swap back magic_quotes - if ($this->magic_quotes_status == 1) { - @set_magic_quotes_runtime($this->magic_quotes_status); - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - } - // End of class - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathReduction() - // Description : - // Parameters : - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilPathReduction($p_dir) - { - $v_result = ""; - - // ----- Look for not empty path - if ($p_dir != "") { - // ----- Explode path by directory names - $v_list = explode("/", $p_dir); - - // ----- Study directories from last to first - $v_skip = 0; - for ($i=sizeof($v_list)-1; $i>=0; $i--) { - // ----- Look for current path - if ($v_list[$i] == ".") { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") { - $v_skip++; - } - else if ($v_list[$i] == "") { - // ----- First '/' i.e. root slash - if ($i == 0) { - $v_result = "/".$v_result; - if ($v_skip > 0) { - // ----- It is an invalid path, so the path is not modified - // TBC - $v_result = $p_dir; - $v_skip = 0; - } - } - // ----- Last '/' i.e. indicates a directory - else if ($i == (sizeof($v_list)-1)) { - $v_result = $v_list[$i]; - } - // ----- Double '/' inside the path - else { - // ----- Ignore only the double '//' in path, - // but not the first and last '/' - } - } - else { - // ----- Look for item to skip - if ($v_skip > 0) { - $v_skip--; - } - else { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); - } - } - } - - // ----- Look for skip - if ($v_skip > 0) { - while ($v_skip > 0) { - $v_result = '../'.$v_result; - $v_skip--; - } - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilPathInclusion() - // Description : - // This function indicates if the path $p_path is under the $p_dir tree. Or, - // said in an other way, if the file or sub-dir $p_path is inside the dir - // $p_dir. - // The function indicates also if the path is exactly the same as the dir. - // This function supports path with duplicated '/' like '//', but does not - // support '.' or '..' statements. - // Parameters : - // Return Values : - // 0 if $p_path is not inside directory $p_dir - // 1 if $p_path is inside directory $p_dir - // 2 if $p_path is exactly the same as $p_dir - // -------------------------------------------------------------------------------- - function PclZipUtilPathInclusion($p_dir, $p_path) - { - $v_result = 1; - - // ----- Look for path beginning by ./ - if ( ($p_dir == '.') - || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { - $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); - } - if ( ($p_path == '.') - || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { - $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); - } - - // ----- Explode dir and path by directory separator - $v_list_dir = explode("/", $p_dir); - $v_list_dir_size = sizeof($v_list_dir); - $v_list_path = explode("/", $p_path); - $v_list_path_size = sizeof($v_list_path); - - // ----- Study directories paths - $i = 0; - $j = 0; - while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { - - // ----- Look for empty dir (path reduction) - if ($v_list_dir[$i] == '') { - $i++; - continue; - } - if ($v_list_path[$j] == '') { - $j++; - continue; - } - - // ----- Compare the items - if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { - $v_result = 0; - } - - // ----- Next items - $i++; - $j++; - } - - // ----- Look if everything seems to be the same - if ($v_result) { - // ----- Skip all the empty items - while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; - while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; - - if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { - // ----- There are exactly the same - $v_result = 2; - } - else if ($i < $v_list_dir_size) { - // ----- The path is shorter than the dir - $v_result = 0; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilCopyBlock() - // Description : - // Parameters : - // $p_mode : read/write compression mode - // 0 : src & dest normal - // 1 : src gzip, dest normal - // 2 : src normal, dest gzip - // 3 : src & dest gzip - // Return Values : - // -------------------------------------------------------------------------------- - function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) - { - $v_result = 1; - - if ($p_mode==0) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==1) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==2) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==3) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilRename() - // Description : - // This function tries to do a simple rename() function. If it fails, it - // tries to copy the $p_src file in a new $p_dest file and then unlink the - // first one. - // Parameters : - // $p_src : Old filename - // $p_dest : New filename - // Return Values : - // 1 on success, 0 on failure. - // -------------------------------------------------------------------------------- - function PclZipUtilRename($p_src, $p_dest) - { - $v_result = 1; - - // ----- Try to rename the files - if (!@rename($p_src, $p_dest)) { - - // ----- Try to copy & unlink the src - if (!@copy($p_src, $p_dest)) { - $v_result = 0; - } - else if (!@unlink($p_src)) { - $v_result = 0; - } - } - - // ----- Return - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilOptionText() - // Description : - // Translate option value in text. Mainly for debug purpose. - // Parameters : - // $p_option : the option value. - // Return Values : - // The option text value. - // -------------------------------------------------------------------------------- - function PclZipUtilOptionText($p_option) - { - - $v_list = get_defined_constants(); - for (reset($v_list); $v_key = key($v_list); next($v_list)) { - $v_prefix = substr($v_key, 0, 10); - if (( ($v_prefix == 'PCLZIP_OPT') - || ($v_prefix == 'PCLZIP_CB_') - || ($v_prefix == 'PCLZIP_ATT')) - && ($v_list[$v_key] == $p_option)) { - return $v_key; - } - } - - $v_result = 'Unknown'; - - return $v_result; - } - // -------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------- - // Function : PclZipUtilTranslateWinPath() - // Description : - // Translate windows path by replacing '\' by '/' and optionally removing - // drive letter. - // Parameters : - // $p_path : path to translate. - // $p_remove_disk_letter : true | false - // Return Values : - // The path translated. - // -------------------------------------------------------------------------------- - function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) - { - if (stristr(php_uname(), 'windows')) { - // ----- Look for potential disk letter - if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } - } - return $p_path; - } - // -------------------------------------------------------------------------------- - - -?> +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function create($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Invalid number / type of arguments"); + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + else { + } + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function add($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + function listContent() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function extract() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Trace + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, + $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + function extractByIndex($p_index) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + } + else { + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, + array (PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function delete() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + function properties() + { + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) + { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) + { + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) + { + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } + else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + function merge($p_archive_to_add) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) + { + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) + { + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorCode()); + } + else { + return($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorName($p_with_code=false) + { + $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' + ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' + ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->error_code.')'); + } + else { + return($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorInfo($p_full=false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorString()); + } + else { + if ($p_full) { + return($this->errorName(true)." : ".$this->error_string); + } + else { + return($this->error_string." [code ".$this->error_code."]"); + } + } + } + // -------------------------------------------------------------------------------- + + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + function privCheckFormat($p_level=0) + { + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) + { + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH : + case PCLZIP_OPT_REMOVE_PATH : + case PCLZIP_OPT_ADD_PATH : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i+1]; + if ((!is_integer($v_value)) || ($v_value<0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value*1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if ( is_string($p_options_list[$i+1]) + && ($p_options_list[$i+1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + } + else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + case PCLZIP_OPT_BY_PREG : + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT : + case PCLZIP_OPT_ADD_COMMENT : + case PCLZIP_OPT_PREPEND_COMMENT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, + "Missing parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, + "Wrong parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + + // ----- Remove spaces + $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i+1]); + } + else if (is_integer($p_options_list[$i+1])) { + $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_work_list = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag=false; + $v_sort_value=0; + for ($j=0; $j= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT : + case PCLZIP_CB_POST_EXTRACT : + case PCLZIP_CB_PRE_ADD : + case PCLZIP_CB_POST_ADD : + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '" + .$p_options_list[$i]."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privOptionDefaultThreshold(&$p_options) + { + $v_result=1; + + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } + + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + + if($last == 'g') + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit*1073741824; + if($last == 'm') + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit*1048576; + if($last == 'k') + $v_memory_limit = $v_memory_limit*1024; + + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + + + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) + { + $v_result=1; + + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + break; + + case PCLZIP_ATT_FILE_NEW_SHORT_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + case PCLZIP_ATT_FILE_NEW_FULL_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME : + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT : + $p_filedescr['content'] = $v_value; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '".$v_key."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result=1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) + && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; + } + else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } + else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } + else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + $v_result=1; + + // ----- Look if already open + if ($this->zip_fd != 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- +// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, + $p_options); + if ($v_result != 1) { + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=1; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } + else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; +// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; + $p_header['stored_filename'] = $p_filedescr['stored_filename']; + $p_header['extra'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for regular file + if ($p_filedescr['type']=='file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for regular folder + else if ($p_filedescr['type']=='folder') { + $p_header['external'] = 0x00000010; + $p_header['mtime'] = filemtime($p_filename); + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for virtual file + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = strlen($p_filedescr['content']); + } + + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = time(); + } + else { + $p_header['mtime'] = filemtime($p_filename); + } + + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } + else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Use "in memory" zip algo + else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + } + + // ----- Look for a virtual file (a file from string) + else if ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + } + + // ----- Look for a directory + else if ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) + { + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); + + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); + return PclZip::errorCode(); + } + + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); + + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) + { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCalculateStoredFilename(&$p_filedescr, &$p_options) + { + $v_result=1; + + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } + else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } + else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + else { + $p_remove_all_dir = 0; + } + + + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + } + + // ----- Look for path and/or short name change + else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'].'/'; + } + $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; + } + else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ( (substr($p_filename, 0, 2) == "./") + || (substr($p_remove_dir, 0, 2) == "./")) { + + if ( (substr($p_filename, 0, 2) == "./") + && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./".$p_remove_dir; + } + if ( (substr($p_filename, 0, 2) != "./") + && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, + $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } + else { + $v_stored_filename = substr($v_stored_filename, + strlen($p_remove_dir)); + } + } + } + + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); + + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + $v_result=1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, + $p_header['version_extracted'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], + $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, + $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], + $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], + $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, + $p_nb_entries, $p_size, + $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privConvertHeader2FileInfo($p_header, &$p_info) + { + $v_result=1; + + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if ( ($p_path == "") + || ( (substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") + && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) + { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") + { + $p_path = substr($p_path, 0, strlen($p_path)-1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) + { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for extraction in standard output + elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) + && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for normal extraction + else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, + $p_path, $p_remove_path, + $p_remove_all_path, + $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external']&0x00000010)==0x00000010) { + + $p_entry['status'] = "filtered"; + + return $v_result; + } + + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion + = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], + $p_entry['filename']); + if ($v_inclusion == 0) { + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, + "Filename '".$p_entry['filename']."' is " + ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + } + else { + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + return PclZip::errorCode(); + } + } + } + else { + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + + } + else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); + return PclZip::errorCode(); + } + + + // ----- Look for using temporary file to unzip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Look for extract in memory + else { + + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === FALSE) { + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + } + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); + + // ----- Close the temporary file + @fclose($v_dest_file); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + $p_entry['status'] = "write_error"; + return $v_result; + } + + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + @fclose($v_dest_file); + @gzclose($v_src_file); + + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } + else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === FALSE) { + // TBC + } + } + + // ----- Trace + } + else { + // TBC : error : can not extract a folder in a string + } + + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + + // ----- Get extra + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + + // ----- Get comment + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } + + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size-22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) + { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, + 'The central dir is not at the end of the archive.' + .' Some trailing bytes exists after the archive.'); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } + else + $p_central_dir['comment'] = ''; + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + + return $v_result; + } + + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + else { + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + unset($v_header_list[$v_nb_extracted]); + } + else + { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $izip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, + $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Remove every files : reset the file + else if ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + function privDirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) + { + // ----- Look for parent directory + if ($p_parent_dir != "") + { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) + { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privMerge(&$p_archive_to_add) + { + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Open the archive_to_add file + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorLog($p_error_code=0, $p_error_string='') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } + else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } + else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + $v_skip++; + } + else if ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/".$v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + } + // ----- Last '/' i.e. indicates a directory + else if ($i == (sizeof($v_list)-1)) { + $v_result = $v_list[$i]; + } + // ----- Double '/' inside the path + else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } + else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } + else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../'.$v_result; + $v_skip--; + } + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // -------------------------------------------------------------------------------- + function PclZipUtilPathInclusion($p_dir, $p_path) + { + $v_result = 1; + + // ----- Look for path beginning by ./ + if ( ($p_dir == '.') + || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + } + if ( ($p_path == '.') + || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + } + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilCopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + $v_result = 1; + + if ($p_mode==0) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilRename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // -------------------------------------------------------------------------------- + function PclZipUtilRename($p_src, $p_dest) + { + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } + else if (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilOptionText() + // Description : + // Translate option value in text. Mainly for debug purpose. + // Parameters : + // $p_option : the option value. + // Return Values : + // The option text value. + // -------------------------------------------------------------------------------- + function PclZipUtilOptionText($p_option) + { + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if (( ($v_prefix == 'PCLZIP_OPT') + || ($v_prefix == 'PCLZIP_CB_') + || ($v_prefix == 'PCLZIP_ATT')) + && ($v_list[$v_key] == $p_option)) { + return $v_key; + } + } + + $v_result = 'Unknown'; + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilTranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // -------------------------------------------------------------------------------- + function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // -------------------------------------------------------------------------------- + + +?> diff --git a/lib/phpmailer/class.smtp.php b/lib/phpmailer/class.smtp.php index c2ca1cb3b8..c664d971eb 100644 --- a/lib/phpmailer/class.smtp.php +++ b/lib/phpmailer/class.smtp.php @@ -1,814 +1,814 @@ -smtp_conn = 0; - $this->error = null; - $this->helo_rply = null; - - $this->do_debug = 0; - } - - ///////////////////////////////////////////////// - // CONNECTION FUNCTIONS - ///////////////////////////////////////////////// - - /** - * Connect to the server specified on the port specified. - * If the port is not specified use the default SMTP_PORT. - * If tval is specified then a connection will try and be - * established with the server for that number of seconds. - * If tval is not specified the default is 30 seconds to - * try on the connection. - * - * SMTP CODE SUCCESS: 220 - * SMTP CODE FAILURE: 421 - * @access public - * @return bool - */ - public function Connect($host, $port = 0, $tval = 30) { - // set the error val to null so there is no confusion - $this->error = null; - - // make sure we are __not__ connected - if($this->connected()) { - // already connected, generate error - $this->error = array("error" => "Already connected to a server"); - return false; - } - - if(empty($port)) { - $port = $this->SMTP_PORT; - } - - // connect to the smtp server - $this->smtp_conn = @fsockopen($host, // the host of the server - $port, // the port to use - $errno, // error number if any - $errstr, // error message if any - $tval); // give up after ? secs - // verify we connected properly - if(empty($this->smtp_conn)) { - $this->error = array("error" => "Failed to connect to server", - "errno" => $errno, - "errstr" => $errstr); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '
'; - } - return false; - } - - // SMTP server can take longer to respond, give longer timeout for first read - // Windows does not have support for this timeout function - if(substr(PHP_OS, 0, 3) != "WIN") - socket_set_timeout($this->smtp_conn, $tval, 0); - - // get any announcement - $announce = $this->get_lines(); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '
'; - } - - return true; - } - - /** - * Initiate a TLS communication with the server. - * - * SMTP CODE 220 Ready to start TLS - * SMTP CODE 501 Syntax error (no parameters allowed) - * SMTP CODE 454 TLS not available due to temporary reason - * @access public - * @return bool success - */ - public function StartTLS() { - $this->error = null; # to avoid confusion - - if(!$this->connected()) { - $this->error = array("error" => "Called StartTLS() without being connected"); - return false; - } - - fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 220) { - $this->error = - array("error" => "STARTTLS not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - // Begin encrypted connection - if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { - return false; - } - - return true; - } - - /** - * Performs SMTP authentication. Must be run after running the - * Hello() method. Returns true if successfully authenticated. - * @access public - * @return bool - */ - public function Authenticate($username, $password) { - // Start authentication - fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 334) { - $this->error = - array("error" => "AUTH not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - // Send encoded username - fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 334) { - $this->error = - array("error" => "Username not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - // Send encoded password - fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($code != 235) { - $this->error = - array("error" => "Password not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - return true; - } - - /** - * Returns true if connected to a server otherwise false - * @access public - * @return bool - */ - public function Connected() { - if(!empty($this->smtp_conn)) { - $sock_status = socket_get_status($this->smtp_conn); - if($sock_status["eof"]) { - // the socket is valid but we are not connected - if($this->do_debug >= 1) { - echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected"; - } - $this->Close(); - return false; - } - return true; // everything looks good - } - return false; - } - - /** - * Closes the socket and cleans up the state of the class. - * It is not considered good to use this function without - * first trying to use QUIT. - * @access public - * @return void - */ - public function Close() { - $this->error = null; // so there is no confusion - $this->helo_rply = null; - if(!empty($this->smtp_conn)) { - // close the connection and cleanup - fclose($this->smtp_conn); - $this->smtp_conn = 0; - } - } - - ///////////////////////////////////////////////// - // SMTP COMMANDS - ///////////////////////////////////////////////// - - /** - * Issues a data command and sends the msg_data to the server - * finializing the mail transaction. $msg_data is the message - * that is to be send with the headers. Each header needs to be - * on a single line followed by a with the message headers - * and the message body being seperated by and additional . - * - * Implements rfc 821: DATA - * - * SMTP CODE INTERMEDIATE: 354 - * [data] - * . - * SMTP CODE SUCCESS: 250 - * SMTP CODE FAILURE: 552,554,451,452 - * SMTP CODE FAILURE: 451,554 - * SMTP CODE ERROR : 500,501,503,421 - * @access public - * @return bool - */ - public function Data($msg_data) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Data() without being connected"); - return false; - } - - fputs($this->smtp_conn,"DATA" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 354) { - $this->error = - array("error" => "DATA command not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - /* the server is ready to accept data! - * according to rfc 821 we should not send more than 1000 - * including the CRLF - * characters on a single line so we will break the data up - * into lines by \r and/or \n then if needed we will break - * each of those into smaller lines to fit within the limit. - * in addition we will be looking for lines that start with - * a period '.' and append and additional period '.' to that - * line. NOTE: this does not count towards limit. - */ - - // normalize the line breaks so we know the explode works - $msg_data = str_replace("\r\n","\n",$msg_data); - $msg_data = str_replace("\r","\n",$msg_data); - $lines = explode("\n",$msg_data); - - /* we need to find a good way to determine is headers are - * in the msg_data or if it is a straight msg body - * currently I am assuming rfc 822 definitions of msg headers - * and if the first field of the first line (':' sperated) - * does not contain a space then it _should_ be a header - * and we can process all lines before a blank "" line as - * headers. - */ - - $field = substr($lines[0],0,strpos($lines[0],":")); - $in_headers = false; - if(!empty($field) && !strstr($field," ")) { - $in_headers = true; - } - - $max_line_length = 998; // used below; set here for ease in change - - while(list(,$line) = @each($lines)) { - $lines_out = null; - if($line == "" && $in_headers) { - $in_headers = false; - } - // ok we need to break this line up into several smaller lines - while(strlen($line) > $max_line_length) { - $pos = strrpos(substr($line,0,$max_line_length)," "); - - // Patch to fix DOS attack - if(!$pos) { - $pos = $max_line_length - 1; - $lines_out[] = substr($line,0,$pos); - $line = substr($line,$pos); - } else { - $lines_out[] = substr($line,0,$pos); - $line = substr($line,$pos + 1); - } - - /* if processing headers add a LWSP-char to the front of new line - * rfc 822 on long msg headers - */ - if($in_headers) { - $line = "\t" . $line; - } - } - $lines_out[] = $line; - - // send the lines to the server - while(list(,$line_out) = @each($lines_out)) { - if(strlen($line_out) > 0) - { - if(substr($line_out, 0, 1) == ".") { - $line_out = "." . $line_out; - } - } - fputs($this->smtp_conn,$line_out . $this->CRLF); - } - } - - // message data has been sent - fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 250) { - $this->error = - array("error" => "DATA not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - return true; - } - - /** - * Sends the HELO command to the smtp server. - * This makes sure that we and the server are in - * the same known state. - * - * Implements from rfc 821: HELO - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE ERROR : 500, 501, 504, 421 - * @access public - * @return bool - */ - public function Hello($host = '') { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Hello() without being connected"); - return false; - } - - // if hostname for HELO was not specified send default - if(empty($host)) { - // determine appropriate default to send to server - $host = "localhost"; - } - - // Send extended hello first (RFC 2821) - if(!$this->SendHello("EHLO", $host)) { - if(!$this->SendHello("HELO", $host)) { - return false; - } - } - - return true; - } - - /** - * Sends a HELO/EHLO command. - * @access private - * @return bool - */ - private function SendHello($hello, $host) { - fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '
'; - } - - if($code != 250) { - $this->error = - array("error" => $hello . " not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - $this->helo_rply = $rply; - - return true; - } - - /** - * Starts a mail transaction from the email address specified in - * $from. Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more Recipient - * commands may be called followed by a Data command. - * - * Implements rfc 821: MAIL FROM: - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE SUCCESS: 552,451,452 - * SMTP CODE SUCCESS: 500,501,421 - * @access public - * @return bool - */ - public function Mail($from) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Mail() without being connected"); - return false; - } - - $useVerp = ($this->do_verp ? "XVERP" : ""); - fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 250) { - $this->error = - array("error" => "MAIL not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - return true; - } - - /** - * Sends the quit command to the server and then closes the socket - * if there is no error or the $close_on_error argument is true. - * - * Implements from rfc 821: QUIT - * - * SMTP CODE SUCCESS: 221 - * SMTP CODE ERROR : 500 - * @access public - * @return bool - */ - public function Quit($close_on_error = true) { - $this->error = null; // so there is no confusion - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Quit() without being connected"); - return false; - } - - // send the quit command to the server - fputs($this->smtp_conn,"quit" . $this->CRLF); - - // get any good-bye messages - $byemsg = $this->get_lines(); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '
'; - } - - $rval = true; - $e = null; - - $code = substr($byemsg,0,3); - if($code != 221) { - // use e as a tmp var cause Close will overwrite $this->error - $e = array("error" => "SMTP server rejected quit command", - "smtp_code" => $code, - "smtp_rply" => substr($byemsg,4)); - $rval = false; - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '
'; - } - } - - if(empty($e) || $close_on_error) { - $this->Close(); - } - - return $rval; - } - - /** - * Sends the command RCPT to the SMTP server with the TO: argument of $to. - * Returns true if the recipient was accepted false if it was rejected. - * - * Implements from rfc 821: RCPT TO: - * - * SMTP CODE SUCCESS: 250,251 - * SMTP CODE FAILURE: 550,551,552,553,450,451,452 - * SMTP CODE ERROR : 500,501,503,421 - * @access public - * @return bool - */ - public function Recipient($to) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Recipient() without being connected"); - return false; - } - - fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 250 && $code != 251) { - $this->error = - array("error" => "RCPT not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - return true; - } - - /** - * Sends the RSET command to abort and transaction that is - * currently in progress. Returns true if successful false - * otherwise. - * - * Implements rfc 821: RSET - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE ERROR : 500,501,504,421 - * @access public - * @return bool - */ - public function Reset() { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called Reset() without being connected"); - return false; - } - - fputs($this->smtp_conn,"RSET" . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 250) { - $this->error = - array("error" => "RSET failed", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - - return true; - } - - /** - * Starts a mail transaction from the email address specified in - * $from. Returns true if successful or false otherwise. If True - * the mail transaction is started and then one or more Recipient - * commands may be called followed by a Data command. This command - * will send the message to the users terminal if they are logged - * in and send them an email. - * - * Implements rfc 821: SAML FROM: - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE SUCCESS: 552,451,452 - * SMTP CODE SUCCESS: 500,501,502,421 - * @access public - * @return bool - */ - public function SendAndMail($from) { - $this->error = null; // so no confusion is caused - - if(!$this->connected()) { - $this->error = array( - "error" => "Called SendAndMail() without being connected"); - return false; - } - - fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); - - $rply = $this->get_lines(); - $code = substr($rply,0,3); - - if($this->do_debug >= 2) { - echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; - } - - if($code != 250) { - $this->error = - array("error" => "SAML not accepted from server", - "smtp_code" => $code, - "smtp_msg" => substr($rply,4)); - if($this->do_debug >= 1) { - echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; - } - return false; - } - return true; - } - - /** - * This is an optional command for SMTP that this class does not - * support. This method is here to make the RFC821 Definition - * complete for this class and __may__ be implimented in the future - * - * Implements from rfc 821: TURN - * - * SMTP CODE SUCCESS: 250 - * SMTP CODE FAILURE: 502 - * SMTP CODE ERROR : 500, 503 - * @access public - * @return bool - */ - public function Turn() { - $this->error = array("error" => "This method, TURN, of the SMTP ". - "is not implemented"); - if($this->do_debug >= 1) { - echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '
'; - } - return false; - } - - /** - * Get the current error - * @access public - * @return array - */ - public function getError() { - return $this->error; - } - - ///////////////////////////////////////////////// - // INTERNAL FUNCTIONS - ///////////////////////////////////////////////// - - /** - * Read in as many lines as possible - * either before eof or socket timeout occurs on the operation. - * With SMTP we can tell if we have more lines to read if the - * 4th character is '-' symbol. If it is a space then we don't - * need to read anything else. - * @access private - * @return string - */ - private function get_lines() { - $data = ""; - while($str = @fgets($this->smtp_conn,515)) { - if($this->do_debug >= 4) { - echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '
'; - echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '
'; - } - $data .= $str; - if($this->do_debug >= 4) { - echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '
'; - } - // if 4th character is a space, we are done reading, break the loop - if(substr($str,3,1) == " ") { break; } - } - return $data; - } - -} - +smtp_conn = 0; + $this->error = null; + $this->helo_rply = null; + + $this->do_debug = 0; + } + + ///////////////////////////////////////////////// + // CONNECTION FUNCTIONS + ///////////////////////////////////////////////// + + /** + * Connect to the server specified on the port specified. + * If the port is not specified use the default SMTP_PORT. + * If tval is specified then a connection will try and be + * established with the server for that number of seconds. + * If tval is not specified the default is 30 seconds to + * try on the connection. + * + * SMTP CODE SUCCESS: 220 + * SMTP CODE FAILURE: 421 + * @access public + * @return bool + */ + public function Connect($host, $port = 0, $tval = 30) { + // set the error val to null so there is no confusion + $this->error = null; + + // make sure we are __not__ connected + if($this->connected()) { + // already connected, generate error + $this->error = array("error" => "Already connected to a server"); + return false; + } + + if(empty($port)) { + $port = $this->SMTP_PORT; + } + + // connect to the smtp server + $this->smtp_conn = @fsockopen($host, // the host of the server + $port, // the port to use + $errno, // error number if any + $errstr, // error message if any + $tval); // give up after ? secs + // verify we connected properly + if(empty($this->smtp_conn)) { + $this->error = array("error" => "Failed to connect to server", + "errno" => $errno, + "errstr" => $errstr); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '
'; + } + return false; + } + + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if(substr(PHP_OS, 0, 3) != "WIN") + socket_set_timeout($this->smtp_conn, $tval, 0); + + // get any announcement + $announce = $this->get_lines(); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '
'; + } + + return true; + } + + /** + * Initiate a TLS communication with the server. + * + * SMTP CODE 220 Ready to start TLS + * SMTP CODE 501 Syntax error (no parameters allowed) + * SMTP CODE 454 TLS not available due to temporary reason + * @access public + * @return bool success + */ + public function StartTLS() { + $this->error = null; # to avoid confusion + + if(!$this->connected()) { + $this->error = array("error" => "Called StartTLS() without being connected"); + return false; + } + + fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 220) { + $this->error = + array("error" => "STARTTLS not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Begin encrypted connection + if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + return false; + } + + return true; + } + + /** + * Performs SMTP authentication. Must be run after running the + * Hello() method. Returns true if successfully authenticated. + * @access public + * @return bool + */ + public function Authenticate($username, $password) { + // Start authentication + fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) { + $this->error = + array("error" => "AUTH not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Send encoded username + fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 334) { + $this->error = + array("error" => "Username not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + // Send encoded password + fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($code != 235) { + $this->error = + array("error" => "Password not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + return true; + } + + /** + * Returns true if connected to a server otherwise false + * @access public + * @return bool + */ + public function Connected() { + if(!empty($this->smtp_conn)) { + $sock_status = socket_get_status($this->smtp_conn); + if($sock_status["eof"]) { + // the socket is valid but we are not connected + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected"; + } + $this->Close(); + return false; + } + return true; // everything looks good + } + return false; + } + + /** + * Closes the socket and cleans up the state of the class. + * It is not considered good to use this function without + * first trying to use QUIT. + * @access public + * @return void + */ + public function Close() { + $this->error = null; // so there is no confusion + $this->helo_rply = null; + if(!empty($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = 0; + } + } + + ///////////////////////////////////////////////// + // SMTP COMMANDS + ///////////////////////////////////////////////// + + /** + * Issues a data command and sends the msg_data to the server + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being seperated by and additional . + * + * Implements rfc 821: DATA + * + * SMTP CODE INTERMEDIATE: 354 + * [data] + * . + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 552,554,451,452 + * SMTP CODE FAILURE: 451,554 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Data($msg_data) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Data() without being connected"); + return false; + } + + fputs($this->smtp_conn,"DATA" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 354) { + $this->error = + array("error" => "DATA command not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + /* the server is ready to accept data! + * according to rfc 821 we should not send more than 1000 + * including the CRLF + * characters on a single line so we will break the data up + * into lines by \r and/or \n then if needed we will break + * each of those into smaller lines to fit within the limit. + * in addition we will be looking for lines that start with + * a period '.' and append and additional period '.' to that + * line. NOTE: this does not count towards limit. + */ + + // normalize the line breaks so we know the explode works + $msg_data = str_replace("\r\n","\n",$msg_data); + $msg_data = str_replace("\r","\n",$msg_data); + $lines = explode("\n",$msg_data); + + /* we need to find a good way to determine is headers are + * in the msg_data or if it is a straight msg body + * currently I am assuming rfc 822 definitions of msg headers + * and if the first field of the first line (':' sperated) + * does not contain a space then it _should_ be a header + * and we can process all lines before a blank "" line as + * headers. + */ + + $field = substr($lines[0],0,strpos($lines[0],":")); + $in_headers = false; + if(!empty($field) && !strstr($field," ")) { + $in_headers = true; + } + + $max_line_length = 998; // used below; set here for ease in change + + while(list(,$line) = @each($lines)) { + $lines_out = null; + if($line == "" && $in_headers) { + $in_headers = false; + } + // ok we need to break this line up into several smaller lines + while(strlen($line) > $max_line_length) { + $pos = strrpos(substr($line,0,$max_line_length)," "); + + // Patch to fix DOS attack + if(!$pos) { + $pos = $max_line_length - 1; + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos); + } else { + $lines_out[] = substr($line,0,$pos); + $line = substr($line,$pos + 1); + } + + /* if processing headers add a LWSP-char to the front of new line + * rfc 822 on long msg headers + */ + if($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + // send the lines to the server + while(list(,$line_out) = @each($lines_out)) { + if(strlen($line_out) > 0) + { + if(substr($line_out, 0, 1) == ".") { + $line_out = "." . $line_out; + } + } + fputs($this->smtp_conn,$line_out . $this->CRLF); + } + } + + // message data has been sent + fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "DATA not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the HELO command to the smtp server. + * This makes sure that we and the server are in + * the same known state. + * + * Implements from rfc 821: HELO + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500, 501, 504, 421 + * @access public + * @return bool + */ + public function Hello($host = '') { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Hello() without being connected"); + return false; + } + + // if hostname for HELO was not specified send default + if(empty($host)) { + // determine appropriate default to send to server + $host = "localhost"; + } + + // Send extended hello first (RFC 2821) + if(!$this->SendHello("EHLO", $host)) { + if(!$this->SendHello("HELO", $host)) { + return false; + } + } + + return true; + } + + /** + * Sends a HELO/EHLO command. + * @access private + * @return bool + */ + private function SendHello($hello, $host) { + fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => $hello . " not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + $this->helo_rply = $rply; + + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. + * + * Implements rfc 821: MAIL FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,421 + * @access public + * @return bool + */ + public function Mail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Mail() without being connected"); + return false; + } + + $useVerp = ($this->do_verp ? "XVERP" : ""); + fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "MAIL not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the quit command to the server and then closes the socket + * if there is no error or the $close_on_error argument is true. + * + * Implements from rfc 821: QUIT + * + * SMTP CODE SUCCESS: 221 + * SMTP CODE ERROR : 500 + * @access public + * @return bool + */ + public function Quit($close_on_error = true) { + $this->error = null; // so there is no confusion + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Quit() without being connected"); + return false; + } + + // send the quit command to the server + fputs($this->smtp_conn,"quit" . $this->CRLF); + + // get any good-bye messages + $byemsg = $this->get_lines(); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '
'; + } + + $rval = true; + $e = null; + + $code = substr($byemsg,0,3); + if($code != 221) { + // use e as a tmp var cause Close will overwrite $this->error + $e = array("error" => "SMTP server rejected quit command", + "smtp_code" => $code, + "smtp_rply" => substr($byemsg,4)); + $rval = false; + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '
'; + } + } + + if(empty($e) || $close_on_error) { + $this->Close(); + } + + return $rval; + } + + /** + * Sends the command RCPT to the SMTP server with the TO: argument of $to. + * Returns true if the recipient was accepted false if it was rejected. + * + * Implements from rfc 821: RCPT TO: + * + * SMTP CODE SUCCESS: 250,251 + * SMTP CODE FAILURE: 550,551,552,553,450,451,452 + * SMTP CODE ERROR : 500,501,503,421 + * @access public + * @return bool + */ + public function Recipient($to) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Recipient() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250 && $code != 251) { + $this->error = + array("error" => "RCPT not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * Sends the RSET command to abort and transaction that is + * currently in progress. Returns true if successful false + * otherwise. + * + * Implements rfc 821: RSET + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE ERROR : 500,501,504,421 + * @access public + * @return bool + */ + public function Reset() { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called Reset() without being connected"); + return false; + } + + fputs($this->smtp_conn,"RSET" . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "RSET failed", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + + return true; + } + + /** + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more Recipient + * commands may be called followed by a Data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * + * Implements rfc 821: SAML FROM: + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE SUCCESS: 552,451,452 + * SMTP CODE SUCCESS: 500,501,502,421 + * @access public + * @return bool + */ + public function SendAndMail($from) { + $this->error = null; // so no confusion is caused + + if(!$this->connected()) { + $this->error = array( + "error" => "Called SendAndMail() without being connected"); + return false; + } + + fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); + + $rply = $this->get_lines(); + $code = substr($rply,0,3); + + if($this->do_debug >= 2) { + echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '
'; + } + + if($code != 250) { + $this->error = + array("error" => "SAML not accepted from server", + "smtp_code" => $code, + "smtp_msg" => substr($rply,4)); + if($this->do_debug >= 1) { + echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '
'; + } + return false; + } + return true; + } + + /** + * This is an optional command for SMTP that this class does not + * support. This method is here to make the RFC821 Definition + * complete for this class and __may__ be implimented in the future + * + * Implements from rfc 821: TURN + * + * SMTP CODE SUCCESS: 250 + * SMTP CODE FAILURE: 502 + * SMTP CODE ERROR : 500, 503 + * @access public + * @return bool + */ + public function Turn() { + $this->error = array("error" => "This method, TURN, of the SMTP ". + "is not implemented"); + if($this->do_debug >= 1) { + echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '
'; + } + return false; + } + + /** + * Get the current error + * @access public + * @return array + */ + public function getError() { + return $this->error; + } + + ///////////////////////////////////////////////// + // INTERNAL FUNCTIONS + ///////////////////////////////////////////////// + + /** + * Read in as many lines as possible + * either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * @access private + * @return string + */ + private function get_lines() { + $data = ""; + while($str = @fgets($this->smtp_conn,515)) { + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '
'; + echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '
'; + } + $data .= $str; + if($this->do_debug >= 4) { + echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '
'; + } + // if 4th character is a space, we are done reading, break the loop + if(substr($str,3,1) == " ") { break; } + } + return $data; + } + +} + ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-br.php b/lib/phpmailer/language/phpmailer.lang-br.php index 7d64ce4d4c..6afe60b18c 100644 --- a/lib/phpmailer/language/phpmailer.lang-br.php +++ b/lib/phpmailer/language/phpmailer.lang-br.php @@ -1,26 +1,26 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-ca.php b/lib/phpmailer/language/phpmailer.lang-ca.php index 1127567dc8..4a160a21eb 100644 --- a/lib/phpmailer/language/phpmailer.lang-ca.php +++ b/lib/phpmailer/language/phpmailer.lang-ca.php @@ -1,26 +1,26 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-cz.php b/lib/phpmailer/language/phpmailer.lang-cz.php index f9589ca19d..1c8b206392 100644 --- a/lib/phpmailer/language/phpmailer.lang-cz.php +++ b/lib/phpmailer/language/phpmailer.lang-cz.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-de.php b/lib/phpmailer/language/phpmailer.lang-de.php index 165a86f4f7..b2a76ce1b5 100644 --- a/lib/phpmailer/language/phpmailer.lang-de.php +++ b/lib/phpmailer/language/phpmailer.lang-de.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-dk.php b/lib/phpmailer/language/phpmailer.lang-dk.php index 59b58c0fce..b26257316b 100644 --- a/lib/phpmailer/language/phpmailer.lang-dk.php +++ b/lib/phpmailer/language/phpmailer.lang-dk.php @@ -1,26 +1,26 @@ - -*/ - -$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Kunne ikke logge på.'; -$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; -$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data kunne ikke accepteres.'; -//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; -$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; -$PHPMAILER_LANG['execute'] = 'Kunne ikke køre: '; -$PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: '; -$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; -$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; -$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.'; -//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; -$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; -$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.'; -$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; -//$PHPMAILER_LANG['signing'] = 'Signing Error: '; -//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; -//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; -//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fejl: Kunne ikke logge på.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fejl: Data kunne ikke accepteres.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Ukendt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunne ikke køre: '; +$PHPMAILER_LANG['file_access'] = 'Ingen adgang til fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fejl: Kunne ikke åbne filen: '; +$PHPMAILER_LANG['from_failed'] = 'Følgende afsenderadresse er forkert: '; +$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere email funktionen.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.'; +$PHPMAILER_LANG['provide_address'] = 'Du skal indtaste mindst en modtagers emailadresse.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fejl: Følgende modtagere er forkerte: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-es.php b/lib/phpmailer/language/phpmailer.lang-es.php index 0b6982509c..69b6817482 100644 --- a/lib/phpmailer/language/phpmailer.lang-es.php +++ b/lib/phpmailer/language/phpmailer.lang-es.php @@ -1,26 +1,26 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-fi.php b/lib/phpmailer/language/phpmailer.lang-fi.php index 6d7dccee51..12a845aad6 100644 --- a/lib/phpmailer/language/phpmailer.lang-fi.php +++ b/lib/phpmailer/language/phpmailer.lang-fi.php @@ -1,27 +1,27 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-fo.php b/lib/phpmailer/language/phpmailer.lang-fo.php index 704c4772da..6bd9b0a213 100644 --- a/lib/phpmailer/language/phpmailer.lang-fo.php +++ b/lib/phpmailer/language/phpmailer.lang-fo.php @@ -1,27 +1,27 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-fr.php b/lib/phpmailer/language/phpmailer.lang-fr.php index 52e9ae2b99..c99ac3caf9 100644 --- a/lib/phpmailer/language/phpmailer.lang-fr.php +++ b/lib/phpmailer/language/phpmailer.lang-fr.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-hu.php b/lib/phpmailer/language/phpmailer.lang-hu.php index a26648484b..caca0b50f1 100644 --- a/lib/phpmailer/language/phpmailer.lang-hu.php +++ b/lib/phpmailer/language/phpmailer.lang-hu.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-it.php b/lib/phpmailer/language/phpmailer.lang-it.php index 59bf4fb978..fc1fcb8d2e 100644 --- a/lib/phpmailer/language/phpmailer.lang-it.php +++ b/lib/phpmailer/language/phpmailer.lang-it.php @@ -1,27 +1,27 @@ - -*/ - -$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.'; -$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.'; -$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Data non accettati dal server.'; -//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; -$PHPMAILER_LANG['encoding'] = 'Encoding set dei caratteri sconosciuto: '; -$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: '; -$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: '; -$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: '; -$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: '; -$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail'; -//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; -$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente'; -$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato'; -$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato errore: '; -//$PHPMAILER_LANG['signing'] = 'Signing Error: '; -//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; -//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; -//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP Error: Impossibile autenticarsi.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP Error: Impossibile connettersi all\'host SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Error: Data non accettati dal server.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Encoding set dei caratteri sconosciuto: '; +$PHPMAILER_LANG['execute'] = 'Impossibile eseguire l\'operazione: '; +$PHPMAILER_LANG['file_access'] = 'Impossibile accedere al file: '; +$PHPMAILER_LANG['file_open'] = 'File Error: Impossibile aprire il file: '; +$PHPMAILER_LANG['from_failed'] = 'I seguenti indirizzi mittenti hanno generato errore: '; +$PHPMAILER_LANG['instantiate'] = 'Impossibile istanziare la funzione mail'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = 'Deve essere fornito almeno un indirizzo ricevente'; +$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP Error: I seguenti indirizzi destinatari hanno generato errore: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-ja.php b/lib/phpmailer/language/phpmailer.lang-ja.php index 66da1b6a1d..63cfb23b6a 100644 --- a/lib/phpmailer/language/phpmailer.lang-ja.php +++ b/lib/phpmailer/language/phpmailer.lang-ja.php @@ -1,26 +1,26 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-nl.php b/lib/phpmailer/language/phpmailer.lang-nl.php index 355dcdc499..d2c380b09d 100644 --- a/lib/phpmailer/language/phpmailer.lang-nl.php +++ b/lib/phpmailer/language/phpmailer.lang-nl.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-no.php b/lib/phpmailer/language/phpmailer.lang-no.php index bf2f84ee9b..65cb884399 100644 --- a/lib/phpmailer/language/phpmailer.lang-no.php +++ b/lib/phpmailer/language/phpmailer.lang-no.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-pl.php b/lib/phpmailer/language/phpmailer.lang-pl.php index e8bd5124d7..f4fd801d61 100644 --- a/lib/phpmailer/language/phpmailer.lang-pl.php +++ b/lib/phpmailer/language/phpmailer.lang-pl.php @@ -1,25 +1,25 @@ - \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-ro.php b/lib/phpmailer/language/phpmailer.lang-ro.php index 17cddb76b9..f6aa922556 100644 --- a/lib/phpmailer/language/phpmailer.lang-ro.php +++ b/lib/phpmailer/language/phpmailer.lang-ro.php @@ -1,27 +1,27 @@ - -*/ - -$PHPMAILER_LANG['authenticate'] = 'Eroare SMTP: Nu a functionat autentificarea.'; -$PHPMAILER_LANG['connect_host'] = 'Eroare SMTP: Nu m-am putut conecta la adresa SMTP.'; -$PHPMAILER_LANG['data_not_accepted'] = 'Eroare SMTP: Continutul mailului nu a fost acceptat.'; -//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; -$PHPMAILER_LANG['encoding'] = 'Encodare necunoscuta: '; -$PHPMAILER_LANG['execute'] = 'Nu pot executa: '; -$PHPMAILER_LANG['file_access'] = 'Nu pot accesa fisierul: '; -$PHPMAILER_LANG['file_open'] = 'Eroare de fisier: Nu pot deschide fisierul: '; -$PHPMAILER_LANG['from_failed'] = 'Urmatoarele adrese From au dat eroare: '; -$PHPMAILER_LANG['instantiate'] = 'Nu am putut instantia functia mail.'; -//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; -$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.'; -$PHPMAILER_LANG['provide_address'] = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).'; -$PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: '; -//$PHPMAILER_LANG['signing'] = 'Signing Error: '; -//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; -//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; -//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; + +*/ + +$PHPMAILER_LANG['authenticate'] = 'Eroare SMTP: Nu a functionat autentificarea.'; +$PHPMAILER_LANG['connect_host'] = 'Eroare SMTP: Nu m-am putut conecta la adresa SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Eroare SMTP: Continutul mailului nu a fost acceptat.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Encodare necunoscuta: '; +$PHPMAILER_LANG['execute'] = 'Nu pot executa: '; +$PHPMAILER_LANG['file_access'] = 'Nu pot accesa fisierul: '; +$PHPMAILER_LANG['file_open'] = 'Eroare de fisier: Nu pot deschide fisierul: '; +$PHPMAILER_LANG['from_failed'] = 'Urmatoarele adrese From au dat eroare: '; +$PHPMAILER_LANG['instantiate'] = 'Nu am putut instantia functia mail.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.'; +$PHPMAILER_LANG['provide_address'] = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).'; +$PHPMAILER_LANG['recipients_failed'] = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-ru.php b/lib/phpmailer/language/phpmailer.lang-ru.php index 295a56ef49..d6990525de 100644 --- a/lib/phpmailer/language/phpmailer.lang-ru.php +++ b/lib/phpmailer/language/phpmailer.lang-ru.php @@ -1,25 +1,25 @@ - -*/ - -$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: ошибка авторизации.'; -$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к серверу SMTP.'; -$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.'; -//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; -$PHPMAILER_LANG['encoding'] = 'Неизвестный вид кодировки: '; -$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: '; -$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: '; -$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удается открыть файл: '; -$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: '; -$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail.'; -//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; -$PHPMAILER_LANG['provide_address'] = 'Пожалуйста, введите хотя бы один адрес e-mail получателя.'; -$PHPMAILER_LANG['mailer_not_supported'] = ' - почтовый сервер не поддерживается.'; -$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: отправка по следующим адресам получателей не удалась: '; -//$PHPMAILER_LANG['signing'] = 'Signing Error: '; -//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; -//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; -//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; + +*/ + +$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: ошибка авторизации.'; +$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к серверу SMTP.'; +$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Неизвестный вид кодировки: '; +$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: '; +$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: '; +$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удается открыть файл: '; +$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: '; +$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = 'Пожалуйста, введите хотя бы один адрес e-mail получателя.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' - почтовый сервер не поддерживается.'; +$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: отправка по следующим адресам получателей не удалась: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-se.php b/lib/phpmailer/language/phpmailer.lang-se.php index d459667f7d..67e05f59c6 100644 --- a/lib/phpmailer/language/phpmailer.lang-se.php +++ b/lib/phpmailer/language/phpmailer.lang-se.php @@ -1,26 +1,26 @@ - -*/ - -$PHPMAILER_LANG['authenticate'] = 'SMTP fel: Kunde inte autentisera.'; -$PHPMAILER_LANG['connect_host'] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; -$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fel: Data accepterades inte.'; -//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; -$PHPMAILER_LANG['encoding'] = 'Okänt encode-format: '; -$PHPMAILER_LANG['execute'] = 'Kunde inte köra: '; -$PHPMAILER_LANG['file_access'] = 'Ingen åtkomst till fil: '; -$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte öppna fil: '; -$PHPMAILER_LANG['from_failed'] = 'Följande avsändaradress är felaktig: '; -$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.'; -//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; -$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.'; -$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.'; -$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: '; -//$PHPMAILER_LANG['signing'] = 'Signing Error: '; -//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; -//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; -//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; + +*/ + +$PHPMAILER_LANG['authenticate'] = 'SMTP fel: Kunde inte autentisera.'; +$PHPMAILER_LANG['connect_host'] = 'SMTP fel: Kunde inte ansluta till SMTP-server.'; +$PHPMAILER_LANG['data_not_accepted'] = 'SMTP fel: Data accepterades inte.'; +//$PHPMAILER_LANG['empty_message'] = 'Message body empty'; +$PHPMAILER_LANG['encoding'] = 'Okänt encode-format: '; +$PHPMAILER_LANG['execute'] = 'Kunde inte köra: '; +$PHPMAILER_LANG['file_access'] = 'Ingen åtkomst till fil: '; +$PHPMAILER_LANG['file_open'] = 'Fil fel: Kunde inte öppna fil: '; +$PHPMAILER_LANG['from_failed'] = 'Följande avsändaradress är felaktig: '; +$PHPMAILER_LANG['instantiate'] = 'Kunde inte initiera e-postfunktion.'; +//$PHPMAILER_LANG['invalid_email'] = 'Not sending, email address is invalid: '; +$PHPMAILER_LANG['provide_address'] = 'Du måste ange minst en mottagares e-postadress.'; +$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.'; +$PHPMAILER_LANG['recipients_failed'] = 'SMTP fel: Följande mottagare är felaktig: '; +//$PHPMAILER_LANG['signing'] = 'Signing Error: '; +//$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() failed.'; +//$PHPMAILER_LANG['smtp_error'] = 'SMTP server error: '; +//$PHPMAILER_LANG['variable_set'] = 'Cannot set or reset variable: '; ?> \ No newline at end of file diff --git a/lib/phpmailer/language/phpmailer.lang-tr.php b/lib/phpmailer/language/phpmailer.lang-tr.php index 8a069d14d0..d24627a49a 100644 --- a/lib/phpmailer/language/phpmailer.lang-tr.php +++ b/lib/phpmailer/language/phpmailer.lang-tr.php @@ -1,27 +1,27 @@ - \ No newline at end of file diff --git a/module/action/control.php b/module/action/control.php index 8c881a7c2c..564c1e72bc 100644 --- a/module/action/control.php +++ b/module/action/control.php @@ -1,66 +1,66 @@ - - * @package action - * @version $Id$ - * @link http://www.zentao.net - */ -class action extends control -{ - /** - * Trash - * - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function trash($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - /* Header and position. */ - $this->view->header->title = $this->lang->action->trash; - $this->view->position[] = $this->lang->action->trash; - - /* Get deleted objects. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->trashes = $this->action->getTrashes($orderBy, $pager); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->users['system'] = 'system'; - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - $this->display(); - } - - /** - * Undelete an object. - * - * @param int $actionID - * @access public - * @return void - */ - public function undelete($actionID) - { - $this->action->undelete($actionID); - die(js::locate(inlink('trash'), 'parent')); - } -} + + * @package action + * @version $Id$ + * @link http://www.zentao.net + */ +class action extends control +{ + /** + * Trash + * + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function trash($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + /* Header and position. */ + $this->view->header->title = $this->lang->action->trash; + $this->view->position[] = $this->lang->action->trash; + + /* Get deleted objects. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->trashes = $this->action->getTrashes($orderBy, $pager); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->users['system'] = 'system'; + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + $this->display(); + } + + /** + * Undelete an object. + * + * @param int $actionID + * @access public + * @return void + */ + public function undelete($actionID) + { + $this->action->undelete($actionID); + die(js::locate(inlink('trash'), 'parent')); + } +} diff --git a/module/action/lang/zh-cn.php b/module/action/lang/zh-cn.php index 322adcba1d..45187246ae 100644 --- a/module/action/lang/zh-cn.php +++ b/module/action/lang/zh-cn.php @@ -1,181 +1,181 @@ - - * @package action - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->action->common = '系统日志'; -$lang->action->trash = '回收站'; -$lang->action->undelete = '还原'; - -$lang->action->product = '产品'; -$lang->action->project = '项目'; -$lang->action->objectType = '对象类型'; -$lang->action->objectID = '对象ID'; -$lang->action->objectName = '对象名称'; -$lang->action->actor = '操作者'; -$lang->action->action = '动作'; -$lang->action->actionID = '记录ID'; -$lang->action->date = '日期'; -$lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。'; - -$lang->action->dynamic->today = '今天'; -$lang->action->dynamic->yesterday = '昨天'; -$lang->action->dynamic->twoDaysAgo = '前天'; -$lang->action->dynamic->thisWeek = '本周'; -$lang->action->dynamic->lastWeek = '上周'; -$lang->action->dynamic->thisMonth = '本月'; -$lang->action->dynamic->lastMonth = '上月'; -$lang->action->dynamic->all = '所有'; -$lang->action->dynamic->search = '搜索'; - -$lang->action->objectTypes['product'] = '产品'; -$lang->action->objectTypes['story'] = '需求'; -$lang->action->objectTypes['productplan'] = '产品计划'; -$lang->action->objectTypes['release'] = '发布'; -$lang->action->objectTypes['project'] = '项目'; -$lang->action->objectTypes['task'] = '任务'; -$lang->action->objectTypes['build'] = 'Build'; -$lang->action->objectTypes['bug'] = 'Bug'; -$lang->action->objectTypes['case'] = '用例'; -$lang->action->objectTypes['testtask'] = '测试任务'; -$lang->action->objectTypes['user'] = '用户'; -$lang->action->objectTypes['doc'] = '文档'; -$lang->action->objectTypes['doclib'] = '文档库'; -$lang->action->objectTypes['todo'] = 'TODO'; - -/* 用来描述操作历史记录。*/ -$lang->action->desc->common = '$date, $action by $actor' . "\n"; -$lang->action->desc->extra = '$date, $action as $extra by $actor' . "\n"; -$lang->action->desc->opened = '$date, 由 $actor 创建。' . "\n"; -$lang->action->desc->created = '$date, 由 $actor 创建。' . "\n"; -$lang->action->desc->changed = '$date, 由 $actor 变更。' . "\n"; -$lang->action->desc->edited = '$date, 由 $actor 编辑。' . "\n"; -$lang->action->desc->assigned = '$date, 由 $actor 指派给 $extra' . "\n"; -$lang->action->desc->closed = '$date, 由 $actor 关闭。' . "\n"; -$lang->action->desc->deleted = '$date, 由 $actor 删除。' . "\n"; -$lang->action->desc->deletedfile = '$date, 由 $actor 删除了附件:$extra' . "\n"; -$lang->action->desc->editfile = '$date, 由 $actor 编辑了附件:$extra' . "\n"; -$lang->action->desc->erased = '$date, 由 $actor 删除。' . "\n"; -$lang->action->desc->undeleted = '$date, 由 $actor 还原。' . "\n"; -$lang->action->desc->commented = '$date, 由 $actor 添加备注。' . "\n"; -$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n"; -$lang->action->desc->moved = '$date, 由 $actor 移动,之前为 "$extra"' . "\n"; -$lang->action->desc->confirmed = '$date, 由 $actor 确认需求变动,最新版本为#$extra' . "\n"; -$lang->action->desc->bugconfirmed = '$date, 由 $actor 确认Bug' . "\n"; -$lang->action->desc->frombug = '$date, 由 $actor Bug转化而来,Bug编号为 $extra。'; -$lang->action->desc->started = '$date, 由 $actor 启动。' . "\n"; -$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n"; -$lang->action->desc->svncommited = '$date, 由 $actor 提交代码,版本为#$extra' . "\n"; -$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n"; -$lang->action->desc->diff1 = '修改了 %s,旧值为 "%s",新值为 "%s"。
' . "\n"; -$lang->action->desc->diff2 = '修改了 %s,区别为:' . "\n" . '
%s
' . "\n"; -$lang->action->desc->diff3 = '将文件名 %s 改为 %s ' . "\n"; - -/* 用来显示动态信息。*/ -$lang->action->label->created = '创建了'; -$lang->action->label->opened = '创建了'; -$lang->action->label->changed = '变更了'; -$lang->action->label->edited = '编辑了'; -$lang->action->label->assigned = '指派了'; -$lang->action->label->closed = '关闭了'; -$lang->action->label->deleted = '删除了'; -$lang->action->label->deletedfile = '删除附件'; -$lang->action->label->editfile = '编辑附件'; -$lang->action->label->erased = '删除了'; -$lang->action->label->undeleted = '还原了'; -$lang->action->label->commented = '评论了'; -$lang->action->label->activated = '激活了'; -$lang->action->label->resolved = '解决了'; -$lang->action->label->reviewed = '评审了'; -$lang->action->label->moved = '移动了'; -$lang->action->label->confirmed = '确认了需求,'; -$lang->action->label->bugconfirmed = '确认了'; -$lang->action->label->tostory = '转需求'; -$lang->action->label->frombug = '转需求'; -$lang->action->label->totask = '转任务'; -$lang->action->label->svncommited = '提交代码'; -$lang->action->label->linked2plan = '关联计划'; -$lang->action->label->unlinkedfromplan = '移除计划'; -$lang->action->label->linked2project = '关联项目'; -$lang->action->label->unlinkedfromproject = '移除项目'; -$lang->action->label->marked = '编辑了'; -$lang->action->label->started = '开始了'; -$lang->action->label->canceled = '取消了'; -$lang->action->label->finished = '完成了'; -$lang->action->label->login = '登录系统'; -$lang->action->label->logout = "退出登录"; - -/* 用来生成相应对象的链接。*/ -$lang->action->label->product = '产品|product|view|productID=%s'; -$lang->action->label->productplan = '计划|productplan|view|productID=%s'; -$lang->action->label->release = '发布|release|view|productID=%s'; -$lang->action->label->story = '需求|story|view|storyID=%s'; -$lang->action->label->project = '项目|project|view|projectID=%s'; -$lang->action->label->task = '任务|task|view|taskID=%s'; -$lang->action->label->build = 'Build|build|view|buildID=%s'; -$lang->action->label->bug = 'Bug|bug|view|bugID=%s'; -$lang->action->label->case = '用例|testcase|view|caseID=%s'; -$lang->action->label->testtask = '测试任务|testtask|view|caseID=%s'; -$lang->action->label->todo = 'todo|todo|view|todoID=%s'; -$lang->action->label->doclib = '文档库|doc|browse|libID=%s'; -$lang->action->label->doc = '文档|doc|view|docID=%s'; -$lang->action->label->user = '用户'; -$lang->action->label->space = ' '; - -/* Object type. */ -$lang->action->search->objectTypeList[''] = ''; -$lang->action->search->objectTypeList['product'] = '产品'; -$lang->action->search->objectTypeList['project'] = '项目'; -$lang->action->search->objectTypeList['bug'] = 'Bug'; -$lang->action->search->objectTypeList['case'] = '用例'; -$lang->action->search->objectTypeList['story'] = '需求'; -$lang->action->search->objectTypeList['task'] = '任务'; -$lang->action->search->objectTypeList['testtask'] = '测试任务'; -$lang->action->search->objectTypeList['user'] = '用户'; -$lang->action->search->objectTypeList['doc'] = '文档'; -$lang->action->search->objectTypeList['doclib'] = '文档库'; -$lang->action->search->objectTypeList['todo'] = 'TODO'; -$lang->action->search->objectTypeList['build'] = 'Build'; -$lang->action->search->objectTypeList['release'] = '发布'; -$lang->action->search->objectTypeList['productplan'] = '计划'; - -/* 用来在动态显示中显示动作 */ -$lang->action->search->label[''] = ''; -$lang->action->search->label['created'] = $lang->action->label->created; -$lang->action->search->label['opened'] = $lang->action->label->opened; -$lang->action->search->label['changed'] = $lang->action->label->changed; -$lang->action->search->label['edited'] = $lang->action->label->edited; -$lang->action->search->label['assigned'] = $lang->action->label->assigned; -$lang->action->search->label['closed'] = $lang->action->label->closed; -$lang->action->search->label['deleted'] = $lang->action->label->deleted; -$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile; -$lang->action->search->label['editfile'] = $lang->action->label->editfile; -$lang->action->search->label['erased'] = $lang->action->label->erased; -$lang->action->search->label['undeleted'] = $lang->action->label->undeleted; -$lang->action->search->label['commented'] = $lang->action->label->commented; -$lang->action->search->label['activated'] = $lang->action->label->activated; -$lang->action->search->label['resolved'] = $lang->action->label->resolved; -$lang->action->search->label['reviewed'] = $lang->action->label->reviewed; -$lang->action->search->label['moved'] = $lang->action->label->moved; -$lang->action->search->label['confirmed'] = $lang->action->label->confirmed; -$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed; -$lang->action->search->label['tostory'] = $lang->action->label->tostory; -$lang->action->search->label['frombug'] = $lang->action->label->frombug; -$lang->action->search->label['totask'] = $lang->action->label->totask; -$lang->action->search->label['svncommited'] = $lang->action->label->svncommited; -$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan; -$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan; -$lang->action->search->label['linked2project'] = $lang->action->label->linked2project; -$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject; -$lang->action->search->label['marked'] = $lang->action->label->marked; -$lang->action->search->label['started'] = $lang->action->label->started; -$lang->action->search->label['canceled'] = $lang->action->label->canceled; -$lang->action->search->label['finished'] = $lang->action->label->finished; -$lang->action->search->label['login'] = $lang->action->label->login; -$lang->action->search->label['logout'] = $lang->action->label->logout; + + * @package action + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->action->common = '系统日志'; +$lang->action->trash = '回收站'; +$lang->action->undelete = '还原'; + +$lang->action->product = '产品'; +$lang->action->project = '项目'; +$lang->action->objectType = '对象类型'; +$lang->action->objectID = '对象ID'; +$lang->action->objectName = '对象名称'; +$lang->action->actor = '操作者'; +$lang->action->action = '动作'; +$lang->action->actionID = '记录ID'; +$lang->action->date = '日期'; +$lang->action->trashTips = '提示:为了保证系统的完整性,禅道系统的删除都是标记删除。'; + +$lang->action->dynamic->today = '今天'; +$lang->action->dynamic->yesterday = '昨天'; +$lang->action->dynamic->twoDaysAgo = '前天'; +$lang->action->dynamic->thisWeek = '本周'; +$lang->action->dynamic->lastWeek = '上周'; +$lang->action->dynamic->thisMonth = '本月'; +$lang->action->dynamic->lastMonth = '上月'; +$lang->action->dynamic->all = '所有'; +$lang->action->dynamic->search = '搜索'; + +$lang->action->objectTypes['product'] = '产品'; +$lang->action->objectTypes['story'] = '需求'; +$lang->action->objectTypes['productplan'] = '产品计划'; +$lang->action->objectTypes['release'] = '发布'; +$lang->action->objectTypes['project'] = '项目'; +$lang->action->objectTypes['task'] = '任务'; +$lang->action->objectTypes['build'] = 'Build'; +$lang->action->objectTypes['bug'] = 'Bug'; +$lang->action->objectTypes['case'] = '用例'; +$lang->action->objectTypes['testtask'] = '测试任务'; +$lang->action->objectTypes['user'] = '用户'; +$lang->action->objectTypes['doc'] = '文档'; +$lang->action->objectTypes['doclib'] = '文档库'; +$lang->action->objectTypes['todo'] = 'TODO'; + +/* 用来描述操作历史记录。*/ +$lang->action->desc->common = '$date, $action by $actor' . "\n"; +$lang->action->desc->extra = '$date, $action as $extra by $actor' . "\n"; +$lang->action->desc->opened = '$date, 由 $actor 创建。' . "\n"; +$lang->action->desc->created = '$date, 由 $actor 创建。' . "\n"; +$lang->action->desc->changed = '$date, 由 $actor 变更。' . "\n"; +$lang->action->desc->edited = '$date, 由 $actor 编辑。' . "\n"; +$lang->action->desc->assigned = '$date, 由 $actor 指派给 $extra' . "\n"; +$lang->action->desc->closed = '$date, 由 $actor 关闭。' . "\n"; +$lang->action->desc->deleted = '$date, 由 $actor 删除。' . "\n"; +$lang->action->desc->deletedfile = '$date, 由 $actor 删除了附件:$extra' . "\n"; +$lang->action->desc->editfile = '$date, 由 $actor 编辑了附件:$extra' . "\n"; +$lang->action->desc->erased = '$date, 由 $actor 删除。' . "\n"; +$lang->action->desc->undeleted = '$date, 由 $actor 还原。' . "\n"; +$lang->action->desc->commented = '$date, 由 $actor 添加备注。' . "\n"; +$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n"; +$lang->action->desc->moved = '$date, 由 $actor 移动,之前为 "$extra"' . "\n"; +$lang->action->desc->confirmed = '$date, 由 $actor 确认需求变动,最新版本为#$extra' . "\n"; +$lang->action->desc->bugconfirmed = '$date, 由 $actor 确认Bug' . "\n"; +$lang->action->desc->frombug = '$date, 由 $actor Bug转化而来,Bug编号为 $extra。'; +$lang->action->desc->started = '$date, 由 $actor 启动。' . "\n"; +$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n"; +$lang->action->desc->svncommited = '$date, 由 $actor 提交代码,版本为#$extra' . "\n"; +$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n"; +$lang->action->desc->diff1 = '修改了 %s,旧值为 "%s",新值为 "%s"。
' . "\n"; +$lang->action->desc->diff2 = '修改了 %s,区别为:' . "\n" . '
%s
' . "\n"; +$lang->action->desc->diff3 = '将文件名 %s 改为 %s ' . "\n"; + +/* 用来显示动态信息。*/ +$lang->action->label->created = '创建了'; +$lang->action->label->opened = '创建了'; +$lang->action->label->changed = '变更了'; +$lang->action->label->edited = '编辑了'; +$lang->action->label->assigned = '指派了'; +$lang->action->label->closed = '关闭了'; +$lang->action->label->deleted = '删除了'; +$lang->action->label->deletedfile = '删除附件'; +$lang->action->label->editfile = '编辑附件'; +$lang->action->label->erased = '删除了'; +$lang->action->label->undeleted = '还原了'; +$lang->action->label->commented = '评论了'; +$lang->action->label->activated = '激活了'; +$lang->action->label->resolved = '解决了'; +$lang->action->label->reviewed = '评审了'; +$lang->action->label->moved = '移动了'; +$lang->action->label->confirmed = '确认了需求,'; +$lang->action->label->bugconfirmed = '确认了'; +$lang->action->label->tostory = '转需求'; +$lang->action->label->frombug = '转需求'; +$lang->action->label->totask = '转任务'; +$lang->action->label->svncommited = '提交代码'; +$lang->action->label->linked2plan = '关联计划'; +$lang->action->label->unlinkedfromplan = '移除计划'; +$lang->action->label->linked2project = '关联项目'; +$lang->action->label->unlinkedfromproject = '移除项目'; +$lang->action->label->marked = '编辑了'; +$lang->action->label->started = '开始了'; +$lang->action->label->canceled = '取消了'; +$lang->action->label->finished = '完成了'; +$lang->action->label->login = '登录系统'; +$lang->action->label->logout = "退出登录"; + +/* 用来生成相应对象的链接。*/ +$lang->action->label->product = '产品|product|view|productID=%s'; +$lang->action->label->productplan = '计划|productplan|view|productID=%s'; +$lang->action->label->release = '发布|release|view|productID=%s'; +$lang->action->label->story = '需求|story|view|storyID=%s'; +$lang->action->label->project = '项目|project|view|projectID=%s'; +$lang->action->label->task = '任务|task|view|taskID=%s'; +$lang->action->label->build = 'Build|build|view|buildID=%s'; +$lang->action->label->bug = 'Bug|bug|view|bugID=%s'; +$lang->action->label->case = '用例|testcase|view|caseID=%s'; +$lang->action->label->testtask = '测试任务|testtask|view|caseID=%s'; +$lang->action->label->todo = 'todo|todo|view|todoID=%s'; +$lang->action->label->doclib = '文档库|doc|browse|libID=%s'; +$lang->action->label->doc = '文档|doc|view|docID=%s'; +$lang->action->label->user = '用户'; +$lang->action->label->space = ' '; + +/* Object type. */ +$lang->action->search->objectTypeList[''] = ''; +$lang->action->search->objectTypeList['product'] = '产品'; +$lang->action->search->objectTypeList['project'] = '项目'; +$lang->action->search->objectTypeList['bug'] = 'Bug'; +$lang->action->search->objectTypeList['case'] = '用例'; +$lang->action->search->objectTypeList['story'] = '需求'; +$lang->action->search->objectTypeList['task'] = '任务'; +$lang->action->search->objectTypeList['testtask'] = '测试任务'; +$lang->action->search->objectTypeList['user'] = '用户'; +$lang->action->search->objectTypeList['doc'] = '文档'; +$lang->action->search->objectTypeList['doclib'] = '文档库'; +$lang->action->search->objectTypeList['todo'] = 'TODO'; +$lang->action->search->objectTypeList['build'] = 'Build'; +$lang->action->search->objectTypeList['release'] = '发布'; +$lang->action->search->objectTypeList['productplan'] = '计划'; + +/* 用来在动态显示中显示动作 */ +$lang->action->search->label[''] = ''; +$lang->action->search->label['created'] = $lang->action->label->created; +$lang->action->search->label['opened'] = $lang->action->label->opened; +$lang->action->search->label['changed'] = $lang->action->label->changed; +$lang->action->search->label['edited'] = $lang->action->label->edited; +$lang->action->search->label['assigned'] = $lang->action->label->assigned; +$lang->action->search->label['closed'] = $lang->action->label->closed; +$lang->action->search->label['deleted'] = $lang->action->label->deleted; +$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile; +$lang->action->search->label['editfile'] = $lang->action->label->editfile; +$lang->action->search->label['erased'] = $lang->action->label->erased; +$lang->action->search->label['undeleted'] = $lang->action->label->undeleted; +$lang->action->search->label['commented'] = $lang->action->label->commented; +$lang->action->search->label['activated'] = $lang->action->label->activated; +$lang->action->search->label['resolved'] = $lang->action->label->resolved; +$lang->action->search->label['reviewed'] = $lang->action->label->reviewed; +$lang->action->search->label['moved'] = $lang->action->label->moved; +$lang->action->search->label['confirmed'] = $lang->action->label->confirmed; +$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed; +$lang->action->search->label['tostory'] = $lang->action->label->tostory; +$lang->action->search->label['frombug'] = $lang->action->label->frombug; +$lang->action->search->label['totask'] = $lang->action->label->totask; +$lang->action->search->label['svncommited'] = $lang->action->label->svncommited; +$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan; +$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan; +$lang->action->search->label['linked2project'] = $lang->action->label->linked2project; +$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject; +$lang->action->search->label['marked'] = $lang->action->label->marked; +$lang->action->search->label['started'] = $lang->action->label->started; +$lang->action->search->label['canceled'] = $lang->action->label->canceled; +$lang->action->search->label['finished'] = $lang->action->label->finished; +$lang->action->search->label['login'] = $lang->action->label->login; +$lang->action->search->label['logout'] = $lang->action->label->logout; diff --git a/module/action/lang/zh-tw.php b/module/action/lang/zh-tw.php index ed64b00236..4931b2738e 100644 --- a/module/action/lang/zh-tw.php +++ b/module/action/lang/zh-tw.php @@ -1,181 +1,181 @@ - - * @package action - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->action->common = '系統日誌'; -$lang->action->trash = '資源回收筒'; -$lang->action->undelete = '還原'; - -$lang->action->product = '產品'; -$lang->action->project = '項目'; -$lang->action->objectType = '對象類型'; -$lang->action->objectID = '對象ID'; -$lang->action->objectName = '對象名稱'; -$lang->action->actor = '操作者'; -$lang->action->action = '動作'; -$lang->action->actionID = '記錄ID'; -$lang->action->date = '日期'; -$lang->action->trashTips = '提示:為了保證系統的完整性,禪道系統的刪除都是標記刪除。'; - -$lang->action->dynamic->today = '今天'; -$lang->action->dynamic->yesterday = '昨天'; -$lang->action->dynamic->twoDaysAgo = '前天'; -$lang->action->dynamic->thisWeek = '本週'; -$lang->action->dynamic->lastWeek = '上周'; -$lang->action->dynamic->thisMonth = '本月'; -$lang->action->dynamic->lastMonth = '上月'; -$lang->action->dynamic->all = '所有'; -$lang->action->dynamic->search = '搜索'; - -$lang->action->objectTypes['product'] = '產品'; -$lang->action->objectTypes['story'] = '需求'; -$lang->action->objectTypes['productplan'] = '產品計劃'; -$lang->action->objectTypes['release'] = '發佈'; -$lang->action->objectTypes['project'] = '項目'; -$lang->action->objectTypes['task'] = '任務'; -$lang->action->objectTypes['build'] = 'Build'; -$lang->action->objectTypes['bug'] = 'Bug'; -$lang->action->objectTypes['case'] = '用例'; -$lang->action->objectTypes['testtask'] = '測試任務'; -$lang->action->objectTypes['user'] = '用戶'; -$lang->action->objectTypes['doc'] = '文檔'; -$lang->action->objectTypes['doclib'] = '文檔庫'; -$lang->action->objectTypes['todo'] = 'TODO'; - -/* 用來描述操作歷史記錄。*/ -$lang->action->desc->common = '$date, $action by $actor' . "\n"; -$lang->action->desc->extra = '$date, $action as $extra by $actor' . "\n"; -$lang->action->desc->opened = '$date, 由 $actor 創建。' . "\n"; -$lang->action->desc->created = '$date, 由 $actor 創建。' . "\n"; -$lang->action->desc->changed = '$date, 由 $actor 變更。' . "\n"; -$lang->action->desc->edited = '$date, 由 $actor 編輯。' . "\n"; -$lang->action->desc->assigned = '$date, 由 $actor 指派給 $extra' . "\n"; -$lang->action->desc->closed = '$date, 由 $actor 關閉。' . "\n"; -$lang->action->desc->deleted = '$date, 由 $actor 刪除。' . "\n"; -$lang->action->desc->deletedfile = '$date, 由 $actor 刪除了附件:$extra' . "\n"; -$lang->action->desc->editfile = '$date, 由 $actor 編輯了附件:$extra' . "\n"; -$lang->action->desc->erased = '$date, 由 $actor 刪除。' . "\n"; -$lang->action->desc->undeleted = '$date, 由 $actor 還原。' . "\n"; -$lang->action->desc->commented = '$date, 由 $actor 添加備註。' . "\n"; -$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n"; -$lang->action->desc->moved = '$date, 由 $actor 移動,之前為 "$extra"' . "\n"; -$lang->action->desc->confirmed = '$date, 由 $actor 確認需求變動,最新版本為#$extra' . "\n"; -$lang->action->desc->bugconfirmed = '$date, 由 $actor 確認Bug' . "\n"; -$lang->action->desc->frombug = '$date, 由 $actor Bug轉化而來,Bug編號為 $extra。'; -$lang->action->desc->started = '$date, 由 $actor 啟動。' . "\n"; -$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n"; -$lang->action->desc->svncommited = '$date, 由 $actor 提交代碼,版本為#$extra' . "\n"; -$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n"; -$lang->action->desc->diff1 = '修改了 %s,舊值為 "%s",新值為 "%s"。
' . "\n"; -$lang->action->desc->diff2 = '修改了 %s,區別為:' . "\n" . '
%s
' . "\n"; -$lang->action->desc->diff3 = '將檔案名 %s 改為 %s ' . "\n"; - -/* 用來顯示動態信息。*/ -$lang->action->label->created = '創建了'; -$lang->action->label->opened = '創建了'; -$lang->action->label->changed = '變更了'; -$lang->action->label->edited = '編輯了'; -$lang->action->label->assigned = '指派了'; -$lang->action->label->closed = '關閉了'; -$lang->action->label->deleted = '刪除了'; -$lang->action->label->deletedfile = '刪除附件'; -$lang->action->label->editfile = '編輯附件'; -$lang->action->label->erased = '刪除了'; -$lang->action->label->undeleted = '還原了'; -$lang->action->label->commented = '評論了'; -$lang->action->label->activated = '激活了'; -$lang->action->label->resolved = '解決了'; -$lang->action->label->reviewed = '評審了'; -$lang->action->label->moved = '移動了'; -$lang->action->label->confirmed = '確認了需求,'; -$lang->action->label->bugconfirmed = '確認了'; -$lang->action->label->tostory = '轉需求'; -$lang->action->label->frombug = '轉需求'; -$lang->action->label->totask = '轉任務'; -$lang->action->label->svncommited = '提交代碼'; -$lang->action->label->linked2plan = '關聯計劃'; -$lang->action->label->unlinkedfromplan = '移除計劃'; -$lang->action->label->linked2project = '關聯項目'; -$lang->action->label->unlinkedfromproject = '移除項目'; -$lang->action->label->marked = '編輯了'; -$lang->action->label->started = '開始了'; -$lang->action->label->canceled = '取消了'; -$lang->action->label->finished = '完成了'; -$lang->action->label->login = '登錄系統'; -$lang->action->label->logout = "退出登錄"; - -/* 用來生成相應對象的連結。*/ -$lang->action->label->product = '產品|product|view|productID=%s'; -$lang->action->label->productplan = '計劃|productplan|view|productID=%s'; -$lang->action->label->release = '發佈|release|view|productID=%s'; -$lang->action->label->story = '需求|story|view|storyID=%s'; -$lang->action->label->project = '項目|project|view|projectID=%s'; -$lang->action->label->task = '任務|task|view|taskID=%s'; -$lang->action->label->build = 'Build|build|view|buildID=%s'; -$lang->action->label->bug = 'Bug|bug|view|bugID=%s'; -$lang->action->label->case = '用例|testcase|view|caseID=%s'; -$lang->action->label->testtask = '測試任務|testtask|view|caseID=%s'; -$lang->action->label->todo = 'todo|todo|view|todoID=%s'; -$lang->action->label->doclib = '文檔庫|doc|browse|libID=%s'; -$lang->action->label->doc = '文檔|doc|view|docID=%s'; -$lang->action->label->user = '用戶'; -$lang->action->label->space = ' '; - -/* Object type. */ -$lang->action->search->objectTypeList[''] = ''; -$lang->action->search->objectTypeList['product'] = '產品'; -$lang->action->search->objectTypeList['project'] = '項目'; -$lang->action->search->objectTypeList['bug'] = 'Bug'; -$lang->action->search->objectTypeList['case'] = '用例'; -$lang->action->search->objectTypeList['story'] = '需求'; -$lang->action->search->objectTypeList['task'] = '任務'; -$lang->action->search->objectTypeList['testtask'] = '測試任務'; -$lang->action->search->objectTypeList['user'] = '用戶'; -$lang->action->search->objectTypeList['doc'] = '文檔'; -$lang->action->search->objectTypeList['doclib'] = '文檔庫'; -$lang->action->search->objectTypeList['todo'] = 'TODO'; -$lang->action->search->objectTypeList['build'] = 'Build'; -$lang->action->search->objectTypeList['release'] = '發佈'; -$lang->action->search->objectTypeList['productplan'] = '計劃'; - -/* 用來在動態顯示中顯示動作 */ -$lang->action->search->label[''] = ''; -$lang->action->search->label['created'] = $lang->action->label->created; -$lang->action->search->label['opened'] = $lang->action->label->opened; -$lang->action->search->label['changed'] = $lang->action->label->changed; -$lang->action->search->label['edited'] = $lang->action->label->edited; -$lang->action->search->label['assigned'] = $lang->action->label->assigned; -$lang->action->search->label['closed'] = $lang->action->label->closed; -$lang->action->search->label['deleted'] = $lang->action->label->deleted; -$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile; -$lang->action->search->label['editfile'] = $lang->action->label->editfile; -$lang->action->search->label['erased'] = $lang->action->label->erased; -$lang->action->search->label['undeleted'] = $lang->action->label->undeleted; -$lang->action->search->label['commented'] = $lang->action->label->commented; -$lang->action->search->label['activated'] = $lang->action->label->activated; -$lang->action->search->label['resolved'] = $lang->action->label->resolved; -$lang->action->search->label['reviewed'] = $lang->action->label->reviewed; -$lang->action->search->label['moved'] = $lang->action->label->moved; -$lang->action->search->label['confirmed'] = $lang->action->label->confirmed; -$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed; -$lang->action->search->label['tostory'] = $lang->action->label->tostory; -$lang->action->search->label['frombug'] = $lang->action->label->frombug; -$lang->action->search->label['totask'] = $lang->action->label->totask; -$lang->action->search->label['svncommited'] = $lang->action->label->svncommited; -$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan; -$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan; -$lang->action->search->label['linked2project'] = $lang->action->label->linked2project; -$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject; -$lang->action->search->label['marked'] = $lang->action->label->marked; -$lang->action->search->label['started'] = $lang->action->label->started; -$lang->action->search->label['canceled'] = $lang->action->label->canceled; -$lang->action->search->label['finished'] = $lang->action->label->finished; -$lang->action->search->label['login'] = $lang->action->label->login; -$lang->action->search->label['logout'] = $lang->action->label->logout; + + * @package action + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->action->common = '系統日誌'; +$lang->action->trash = '資源回收筒'; +$lang->action->undelete = '還原'; + +$lang->action->product = '產品'; +$lang->action->project = '項目'; +$lang->action->objectType = '對象類型'; +$lang->action->objectID = '對象ID'; +$lang->action->objectName = '對象名稱'; +$lang->action->actor = '操作者'; +$lang->action->action = '動作'; +$lang->action->actionID = '記錄ID'; +$lang->action->date = '日期'; +$lang->action->trashTips = '提示:為了保證系統的完整性,禪道系統的刪除都是標記刪除。'; + +$lang->action->dynamic->today = '今天'; +$lang->action->dynamic->yesterday = '昨天'; +$lang->action->dynamic->twoDaysAgo = '前天'; +$lang->action->dynamic->thisWeek = '本週'; +$lang->action->dynamic->lastWeek = '上周'; +$lang->action->dynamic->thisMonth = '本月'; +$lang->action->dynamic->lastMonth = '上月'; +$lang->action->dynamic->all = '所有'; +$lang->action->dynamic->search = '搜索'; + +$lang->action->objectTypes['product'] = '產品'; +$lang->action->objectTypes['story'] = '需求'; +$lang->action->objectTypes['productplan'] = '產品計劃'; +$lang->action->objectTypes['release'] = '發佈'; +$lang->action->objectTypes['project'] = '項目'; +$lang->action->objectTypes['task'] = '任務'; +$lang->action->objectTypes['build'] = 'Build'; +$lang->action->objectTypes['bug'] = 'Bug'; +$lang->action->objectTypes['case'] = '用例'; +$lang->action->objectTypes['testtask'] = '測試任務'; +$lang->action->objectTypes['user'] = '用戶'; +$lang->action->objectTypes['doc'] = '文檔'; +$lang->action->objectTypes['doclib'] = '文檔庫'; +$lang->action->objectTypes['todo'] = 'TODO'; + +/* 用來描述操作歷史記錄。*/ +$lang->action->desc->common = '$date, $action by $actor' . "\n"; +$lang->action->desc->extra = '$date, $action as $extra by $actor' . "\n"; +$lang->action->desc->opened = '$date, 由 $actor 創建。' . "\n"; +$lang->action->desc->created = '$date, 由 $actor 創建。' . "\n"; +$lang->action->desc->changed = '$date, 由 $actor 變更。' . "\n"; +$lang->action->desc->edited = '$date, 由 $actor 編輯。' . "\n"; +$lang->action->desc->assigned = '$date, 由 $actor 指派給 $extra' . "\n"; +$lang->action->desc->closed = '$date, 由 $actor 關閉。' . "\n"; +$lang->action->desc->deleted = '$date, 由 $actor 刪除。' . "\n"; +$lang->action->desc->deletedfile = '$date, 由 $actor 刪除了附件:$extra' . "\n"; +$lang->action->desc->editfile = '$date, 由 $actor 編輯了附件:$extra' . "\n"; +$lang->action->desc->erased = '$date, 由 $actor 刪除。' . "\n"; +$lang->action->desc->undeleted = '$date, 由 $actor 還原。' . "\n"; +$lang->action->desc->commented = '$date, 由 $actor 添加備註。' . "\n"; +$lang->action->desc->activated = '$date, 由 $actor 激活。' . "\n"; +$lang->action->desc->moved = '$date, 由 $actor 移動,之前為 "$extra"' . "\n"; +$lang->action->desc->confirmed = '$date, 由 $actor 確認需求變動,最新版本為#$extra' . "\n"; +$lang->action->desc->bugconfirmed = '$date, 由 $actor 確認Bug' . "\n"; +$lang->action->desc->frombug = '$date, 由 $actor Bug轉化而來,Bug編號為 $extra。'; +$lang->action->desc->started = '$date, 由 $actor 啟動。' . "\n"; +$lang->action->desc->canceled = '$date, 由 $actor 取消。' . "\n"; +$lang->action->desc->svncommited = '$date, 由 $actor 提交代碼,版本為#$extra' . "\n"; +$lang->action->desc->finished = '$date, 由 $actor 完成。' . "\n"; +$lang->action->desc->diff1 = '修改了 %s,舊值為 "%s",新值為 "%s"。
' . "\n"; +$lang->action->desc->diff2 = '修改了 %s,區別為:' . "\n" . '
%s
' . "\n"; +$lang->action->desc->diff3 = '將檔案名 %s 改為 %s ' . "\n"; + +/* 用來顯示動態信息。*/ +$lang->action->label->created = '創建了'; +$lang->action->label->opened = '創建了'; +$lang->action->label->changed = '變更了'; +$lang->action->label->edited = '編輯了'; +$lang->action->label->assigned = '指派了'; +$lang->action->label->closed = '關閉了'; +$lang->action->label->deleted = '刪除了'; +$lang->action->label->deletedfile = '刪除附件'; +$lang->action->label->editfile = '編輯附件'; +$lang->action->label->erased = '刪除了'; +$lang->action->label->undeleted = '還原了'; +$lang->action->label->commented = '評論了'; +$lang->action->label->activated = '激活了'; +$lang->action->label->resolved = '解決了'; +$lang->action->label->reviewed = '評審了'; +$lang->action->label->moved = '移動了'; +$lang->action->label->confirmed = '確認了需求,'; +$lang->action->label->bugconfirmed = '確認了'; +$lang->action->label->tostory = '轉需求'; +$lang->action->label->frombug = '轉需求'; +$lang->action->label->totask = '轉任務'; +$lang->action->label->svncommited = '提交代碼'; +$lang->action->label->linked2plan = '關聯計劃'; +$lang->action->label->unlinkedfromplan = '移除計劃'; +$lang->action->label->linked2project = '關聯項目'; +$lang->action->label->unlinkedfromproject = '移除項目'; +$lang->action->label->marked = '編輯了'; +$lang->action->label->started = '開始了'; +$lang->action->label->canceled = '取消了'; +$lang->action->label->finished = '完成了'; +$lang->action->label->login = '登錄系統'; +$lang->action->label->logout = "退出登錄"; + +/* 用來生成相應對象的連結。*/ +$lang->action->label->product = '產品|product|view|productID=%s'; +$lang->action->label->productplan = '計劃|productplan|view|productID=%s'; +$lang->action->label->release = '發佈|release|view|productID=%s'; +$lang->action->label->story = '需求|story|view|storyID=%s'; +$lang->action->label->project = '項目|project|view|projectID=%s'; +$lang->action->label->task = '任務|task|view|taskID=%s'; +$lang->action->label->build = 'Build|build|view|buildID=%s'; +$lang->action->label->bug = 'Bug|bug|view|bugID=%s'; +$lang->action->label->case = '用例|testcase|view|caseID=%s'; +$lang->action->label->testtask = '測試任務|testtask|view|caseID=%s'; +$lang->action->label->todo = 'todo|todo|view|todoID=%s'; +$lang->action->label->doclib = '文檔庫|doc|browse|libID=%s'; +$lang->action->label->doc = '文檔|doc|view|docID=%s'; +$lang->action->label->user = '用戶'; +$lang->action->label->space = ' '; + +/* Object type. */ +$lang->action->search->objectTypeList[''] = ''; +$lang->action->search->objectTypeList['product'] = '產品'; +$lang->action->search->objectTypeList['project'] = '項目'; +$lang->action->search->objectTypeList['bug'] = 'Bug'; +$lang->action->search->objectTypeList['case'] = '用例'; +$lang->action->search->objectTypeList['story'] = '需求'; +$lang->action->search->objectTypeList['task'] = '任務'; +$lang->action->search->objectTypeList['testtask'] = '測試任務'; +$lang->action->search->objectTypeList['user'] = '用戶'; +$lang->action->search->objectTypeList['doc'] = '文檔'; +$lang->action->search->objectTypeList['doclib'] = '文檔庫'; +$lang->action->search->objectTypeList['todo'] = 'TODO'; +$lang->action->search->objectTypeList['build'] = 'Build'; +$lang->action->search->objectTypeList['release'] = '發佈'; +$lang->action->search->objectTypeList['productplan'] = '計劃'; + +/* 用來在動態顯示中顯示動作 */ +$lang->action->search->label[''] = ''; +$lang->action->search->label['created'] = $lang->action->label->created; +$lang->action->search->label['opened'] = $lang->action->label->opened; +$lang->action->search->label['changed'] = $lang->action->label->changed; +$lang->action->search->label['edited'] = $lang->action->label->edited; +$lang->action->search->label['assigned'] = $lang->action->label->assigned; +$lang->action->search->label['closed'] = $lang->action->label->closed; +$lang->action->search->label['deleted'] = $lang->action->label->deleted; +$lang->action->search->label['deletedfile'] = $lang->action->label->deletedfile; +$lang->action->search->label['editfile'] = $lang->action->label->editfile; +$lang->action->search->label['erased'] = $lang->action->label->erased; +$lang->action->search->label['undeleted'] = $lang->action->label->undeleted; +$lang->action->search->label['commented'] = $lang->action->label->commented; +$lang->action->search->label['activated'] = $lang->action->label->activated; +$lang->action->search->label['resolved'] = $lang->action->label->resolved; +$lang->action->search->label['reviewed'] = $lang->action->label->reviewed; +$lang->action->search->label['moved'] = $lang->action->label->moved; +$lang->action->search->label['confirmed'] = $lang->action->label->confirmed; +$lang->action->search->label['bugconfirmed'] = $lang->action->label->bugconfirmed; +$lang->action->search->label['tostory'] = $lang->action->label->tostory; +$lang->action->search->label['frombug'] = $lang->action->label->frombug; +$lang->action->search->label['totask'] = $lang->action->label->totask; +$lang->action->search->label['svncommited'] = $lang->action->label->svncommited; +$lang->action->search->label['linked2plan'] = $lang->action->label->linked2plan; +$lang->action->search->label['unlinkedfromplan'] = $lang->action->label->unlinkedfromplan; +$lang->action->search->label['linked2project'] = $lang->action->label->linked2project; +$lang->action->search->label['unlinkedfromproject'] = $lang->action->label->unlinkedfromproject; +$lang->action->search->label['marked'] = $lang->action->label->marked; +$lang->action->search->label['started'] = $lang->action->label->started; +$lang->action->search->label['canceled'] = $lang->action->label->canceled; +$lang->action->search->label['finished'] = $lang->action->label->finished; +$lang->action->search->label['login'] = $lang->action->label->login; +$lang->action->search->label['logout'] = $lang->action->label->logout; diff --git a/module/action/model.php b/module/action/model.php index 0e51c7fe92..5e3c12e2dd 100644 --- a/module/action/model.php +++ b/module/action/model.php @@ -1,552 +1,552 @@ - - * @package action - * @version $Id$ - * @link http://www.zentao.net - */ -?> -objectType = strtolower($objectType); - $action->objectID = $objectID; - $action->actor = $this->app->user->account; - $action->action = strtolower($actionType); - $action->date = helper::now(); - $action->comment = htmlspecialchars($comment); - $action->extra = $extra; - - /* Get product and project for this object. */ - $productAndProject = $this->getProductAndProject($objectType, $objectID); - $action->product = $productAndProject['product']; - $action->project = $productAndProject['project']; - - $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec(); - return $this->dbh->lastInsertID(); - } - - /** - * Get product and project of an object. - * - * @param string $objectType - * @param int $objectID - * @access public - * @return array - */ - public function getProductAndProject($objectType, $objectID) - { - $objectType = strtolower($objectType); - $emptyRecord = array('product' => 0, 'project' => 0); - - /* If objectType is product or project, return the objectID. */ - if($objectType == 'product') return array('product' => $objectID, 'project' => 0); - if($objectType == 'project') - { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($objectID)->fetchPairs('product'); - $productList = ',' . join(',', array_keys($products)) . ','; - return array('project' => $objectID, 'product' => $productList); - } - - /* Only process these object types. */ - if(strpos('story, productplan, release, task, build. bug, case, testtask, doc', $objectType) !== false) - { - if(!isset($this->config->action->objectTables[$objectType])) return $emptyRecord; - - /* Set fields to fetch. */ - if(strpos('story, productplan, case', $objectType) !== false) $fields = 'product'; - if(strpos('build, bug, testtask, doc', $objectType) !== false) $fields = 'product, project'; - if($objectType == 'release') $fields = 'product, build'; - if($objectType == 'task') $fields = 'project, story'; - - $record = $this->dao->select($fields)->from($this->config->action->objectTables[$objectType])->where('id')->eq($objectID)->fetch(); - - /* Process story, release and task. */ - if($objectType == 'story') $record->project = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($objectID)->fetch('project'); - if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project'); - if($objectType == 'task') - { - if($record->story != 0) - { - $product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($record->story)->fetchPairs('product'); - $record->product = ',' . join(',', array_keys($product)) . ','; - } - else - { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($record->project)->fetchPairs('product'); - $record->product = ',' . join(',', array_keys($products)) . ','; - } - } - - if($record) - { - $record = (array)$record; - if(!isset($record['product'])) $record['product'] = 0; - if(!isset($record['project'])) $record['project'] = 0; - return $record; - } - - return $emptyRecord; - } - return $emptyRecord; - } - - /** - * Get actions of an object. - * - * @param int $objectType - * @param int $objectID - * @access public - * @return array - */ - public function getList($objectType, $objectID) - { - $commiters = $this->loadModel('user')->getCommiters(); - $actions = $this->dao->select('*')->from(TABLE_ACTION) - ->where('objectType')->eq($objectType) - ->andWhere('objectID')->eq($objectID) - ->orderBy('date, id')->fetchAll('id'); - $histories = $this->getHistory(array_keys($actions)); - foreach($actions as $actionID => $action) - { - if(strtolower($action->action) == 'svncommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor]; - $action->history = isset($histories[$actionID]) ? $histories[$actionID] : array(); - $actions[$actionID] = $action; - } - return $actions; - } - - /** - * Get an action record. - * - * @param int $actionID - * @access public - * @return object - */ - public function getById($actionID) - { - return $this->dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch(); - } - - /** - * Get deleted objects. - * - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getTrashes($orderBy, $pager) - { - $trashes = $this->dao->select('*')->from(TABLE_ACTION) - ->where('action')->eq('deleted') - ->andWhere('extra')->eq(self::CAN_UNDELETED) - ->orderBy($orderBy)->page($pager)->fetchAll(); - if(!$trashes) return array(); - - /* Group trashes by objectType, and get there name field. */ - foreach($trashes as $object) - { - $object->objectType = str_replace('`', '', $object->objectType); - $typeTrashes[$object->objectType][] = $object->objectID; - } - foreach($typeTrashes as $objectType => $objectIds) - { - $objectIds = array_unique($objectIds); - $table = $this->config->action->objectTables[$objectType]; - $field = $this->config->action->objectNameFields[$objectType]; - $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs(); - } - - /* Add name field to the trashes. */ - foreach($trashes as $trash) $trash->objectName = $objectNames[$trash->objectType][$trash->objectID]; - return $trashes; - } - - /** - * Get histories of an action. - * - * @param int $actionID - * @access public - * @return array - */ - public function getHistory($actionID) - { - return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action'); - } - - /** - * Log histories for an action. - * - * @param int $actionID - * @param array $changes - * @access public - * @return void - */ - public function logHistory($actionID, $changes) - { - foreach($changes as $change) - { - $change['action'] = $actionID; - $this->dao->insert(TABLE_HISTORY)->data($change)->exec(); - } - } - - /** - * Print actions of an object. - * - * @param array $action - * @access public - * @return void - */ - public function printAction($action) - { - $objectType = $action->objectType; - $actionType = strtolower($action->action); - - /** - * Set the desc string of this action. - * - * 1. If the module of this action has defined desc of this actionType, use it. - * 2. If no defined in the module language, search the common action define. - * 3. If not found in the lang->action->desc, use the $lang->action->desc->common or $lang->action->desc->extra as the default. - */ - if(isset($this->lang->$objectType->action->$actionType)) - { - $desc = $this->lang->$objectType->action->$actionType; - } - elseif(isset($this->lang->action->desc->$actionType)) - { - $desc = $this->lang->action->desc->$actionType; - } - else - { - $desc = $action->extra ? $this->lang->action->desc->extra : $this->lang->action->desc->common; - } - - /* Cycle actions, replace vars. */ - foreach($action as $key => $value) - { - if($key == 'history') continue; - - /* Desc can be an array or string. */ - if(is_array($desc)) - { - if($key == 'extra') continue; - $desc['main'] = str_replace('$' . $key, $value, $desc['main']); - } - else - { - $desc = str_replace('$' . $key, $value, $desc); - } - } - - /* If the desc is an array, process extra. Please bug/lang. */ - if(is_array($desc)) - { - $extra = strtolower($action->extra); - if(isset($desc['extra'][$extra])) - { - echo str_replace('$extra', $desc['extra'][$extra], $desc['main']); - } - else - { - echo str_replace('$extra', $action->extra, $desc['main']); - } - } - else - { - echo $desc; - } - } - - /** - * Get actions as dynamic. - * - * @param string $objectType - * @param string $count - * @param string $period - * @param string $orderBy - * @param object $pager - * @param string|int $productID all|int(like 123)|notzero all => include zeror, notzero, great than 0 - * @param string|int $projectID same as productID - * @access public - * @return array - */ - public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all') - { - /* Computer the begin and end date of a period. */ - $period = $this->computeBeginAndEnd($period); - extract($period); - - /* Get actions. */ - $actions = $this->dao->select('*')->from(TABLE_ACTION) - ->where('date')->gt($begin) - ->andWhere('date')->lt($end) - ->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi() - ->beginIF(is_numeric($productID))->andWhere('product')->like("%,$productID,%")->fi() - ->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi() - ->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->fi() - ->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi() - ->orderBy($orderBy)->page($pager)->fetchAll(); - - if(!$actions) return array(); - return $this->transformActions($actions); - } - - /** - * Get dynamic by search. - * - * @param array $products - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getDynamicBySearch($products, $projects, $queryID, $orderBy = 'date_desc', $pager) - { - $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : ''; - - /* Get the sql and form status from the query. */ - if($query) - { - $this->session->set('actionQuery', $query->sql); - $this->session->set('actionForm', $query->form); - } - if($this->session->actionQuery == false) $this->session->set('actionQuery', ' 1 = 1'); - - $allProduct = "`product` = 'all'"; - $allProject = "`project` = 'all'"; - $actionQuery = $this->session->actionQuery; - - $productID = 0; - if(preg_match("/`product` = '(\d*)'/", $actionQuery, $out)) - { - $productID = $out[1]; - } - /* If the sql not include 'product', add check purview for product. */ - if(strpos($actionQuery, $allProduct) === false) - { - if(!in_array($productID, array_keys($products))) return array(); - } - else - { - $actionQuery = str_replace($allProduct, '1', $actionQuery); - } - - /* If the sql not include 'project', add check purview for project. */ - if(strpos($actionQuery, $allProject) === false) - { - $actionQuery = $actionQuery . 'AND `project`' . helper::dbIN(array_keys($projects)); - } - else - { - $actionQuery = str_replace($allProduct, '1', $actionQuery); - } - - $actionQuery = str_replace("`product` = '$productID'", "`product` LIKE '%,$productID,%'", $actionQuery); - - $actions = $this->getBySQL($actionQuery, $orderBy, $pager); - if(!$actions) return array(); - return $this->transformActions($actions); - } - - /** - * Get actions by SQL. - * - * @param string $sql - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getBySQL($sql, $orderBy, $pager = null) - { - return $actions = $this->dao->select('*')->from(TABLE_ACTION) - ->where($sql) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - } - - /** - * Transform the actions for display. - * - * @param int $actions - * @access public - * @return void - */ - public function transformActions($actions) - { - /* Get commiters. */ - $commiters = $this->loadModel('user')->getCommiters(); - - /* Group actions by objectType, and get there name field. */ - foreach($actions as $object) $objectTypes[$object->objectType][] = $object->objectID; - foreach($objectTypes as $objectType => $objectIds) - { - if(!isset($this->config->action->objectTables[$objectType])) continue; // If no defination for this type, omit it. - - $objectIds = array_unique($objectIds); - $table = $this->config->action->objectTables[$objectType]; - $field = $this->config->action->objectNameFields[$objectType]; - if($table != '`zt_todo`') - { - $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs(); - } - else - { - $todos = $this->dao->select("id, $field AS name, account, private")->from($table)->where('id')->in($objectIds)->fetchAll('id'); - foreach($todos as $id => $todo) - { - if($todo->private == 1 and $todo->account != $this->app->user->account) - { - $objectNames[$objectType][$id] = $this->lang->todo->thisIsPrivate; - } - else - { - $objectNames[$objectType][$id] = $todo->name; - } - } - } - } - $objectNames['user'][0] = 'guest'; // Add guest account. - - foreach($actions as $action) - { - /* Add name field to the actions. */ - $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : ''; - - $actionType = strtolower($action->action); - $objectType = strtolower($action->objectType); - $action->date = date(DT_MONTHTIME2, strtotime($action->date)); - $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action; - $action->objectLabel = isset($this->lang->action->label->$objectType) ? $this->lang->action->label->$objectType : $objectType; - - /* If action type is login or logout, needn't link. */ - if($actionType == 'login' or $actionType == 'logout') - { - $action->objectLink = ''; - $action->objectLabel = ''; - continue; - } - elseif($actionType == 'svncommited') - { - $action->actor = isset($commiters[$action->actor]) ? $commiters[$action->actor] : $action->actor; - } - - /* Other actions, create a link. */ - if(strpos($action->objectLabel, '|') !== false) - { - list($objectLabel, $moduleName, $methodName, $vars) = explode('|', $action->objectLabel); - $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID)); - $action->objectLabel = $objectLabel; - } - else - { - $action->objectLink = ''; - } - } - return $actions; - } - - /** - * Compute the begin date and end date of a period. - * - * @param string $period - * @access public - * @return array - */ - public function computeBeginAndEnd($period) - { - $this->loadModel('todo'); - - $today = $this->todo->today(); - $tomorrow = $this->todo->tomorrow(); - $yesterday = $this->todo->yesterday(); - $twoDaysAgo = $this->todo->twoDaysAgo(); - - if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1'); - if($period == 'today') return array('begin' => $today, 'end' => $tomorrow); - if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today); - if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday); - - /* If the period is by week, add the end time to the end date. */ - if($period == 'thisweek' or $period == 'lastweek') - { - $func = "get$period"; - extract($this->todo->$func()); - return array('begin' => $begin, 'end' => $end . ' 23:59:59'); - } - - if($period == 'thismonth') return $this->todo->getThisMonth(); - if($period == 'lastmonth') return $this->todo->getLastMonth(); - } - - /** - * Print changes of every action. - * - * @param string $objectType - * @param array $histories - * @access public - * @return void - */ - public function printChanges($objectType, $histories) - { - if(empty($histories)) return; - - $maxLength = 0; // The max length of fields names. - $historiesWithDiff = array(); // To save histories without diff info. - $historiesWithoutDiff = array(); // To save histories with diff info. - - /* Diff histories by hasing diff info or not. Thus we can to make sure the field with diff show at last. */ - foreach($histories as $history) - { - $fieldName = $history->field; - $history->fieldLabel = isset($this->lang->$objectType->$fieldName) ? $this->lang->$objectType->$fieldName : $fieldName; - if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length; - $history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history; - } - $histories = array_merge($historiesWithoutDiff, $historiesWithDiff); - - foreach($histories as $history) - { - $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space); - if($history->diff != '') - { - $history->diff = str_replace(array('', '', '', ''), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff); - $history->diff = $history->field != 'subversion' ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link. - $history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('', '', '', ''), $history->diff); - $history->diff = nl2br($history->diff); - printf($this->lang->action->desc->diff2, $history->fieldLabel, $history->diff); - } - else - { - printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new); - } - } - } -} + + * @package action + * @version $Id$ + * @link http://www.zentao.net + */ +?> +objectType = strtolower($objectType); + $action->objectID = $objectID; + $action->actor = $this->app->user->account; + $action->action = strtolower($actionType); + $action->date = helper::now(); + $action->comment = htmlspecialchars($comment); + $action->extra = $extra; + + /* Get product and project for this object. */ + $productAndProject = $this->getProductAndProject($objectType, $objectID); + $action->product = $productAndProject['product']; + $action->project = $productAndProject['project']; + + $this->dao->insert(TABLE_ACTION)->data($action)->autoCheck()->exec(); + return $this->dbh->lastInsertID(); + } + + /** + * Get product and project of an object. + * + * @param string $objectType + * @param int $objectID + * @access public + * @return array + */ + public function getProductAndProject($objectType, $objectID) + { + $objectType = strtolower($objectType); + $emptyRecord = array('product' => 0, 'project' => 0); + + /* If objectType is product or project, return the objectID. */ + if($objectType == 'product') return array('product' => $objectID, 'project' => 0); + if($objectType == 'project') + { + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($objectID)->fetchPairs('product'); + $productList = ',' . join(',', array_keys($products)) . ','; + return array('project' => $objectID, 'product' => $productList); + } + + /* Only process these object types. */ + if(strpos('story, productplan, release, task, build. bug, case, testtask, doc', $objectType) !== false) + { + if(!isset($this->config->action->objectTables[$objectType])) return $emptyRecord; + + /* Set fields to fetch. */ + if(strpos('story, productplan, case', $objectType) !== false) $fields = 'product'; + if(strpos('build, bug, testtask, doc', $objectType) !== false) $fields = 'product, project'; + if($objectType == 'release') $fields = 'product, build'; + if($objectType == 'task') $fields = 'project, story'; + + $record = $this->dao->select($fields)->from($this->config->action->objectTables[$objectType])->where('id')->eq($objectID)->fetch(); + + /* Process story, release and task. */ + if($objectType == 'story') $record->project = $this->dao->select('project')->from(TABLE_PROJECTSTORY)->where('story')->eq($objectID)->fetch('project'); + if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project'); + if($objectType == 'task') + { + if($record->story != 0) + { + $product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($record->story)->fetchPairs('product'); + $record->product = ',' . join(',', array_keys($product)) . ','; + } + else + { + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($record->project)->fetchPairs('product'); + $record->product = ',' . join(',', array_keys($products)) . ','; + } + } + + if($record) + { + $record = (array)$record; + if(!isset($record['product'])) $record['product'] = 0; + if(!isset($record['project'])) $record['project'] = 0; + return $record; + } + + return $emptyRecord; + } + return $emptyRecord; + } + + /** + * Get actions of an object. + * + * @param int $objectType + * @param int $objectID + * @access public + * @return array + */ + public function getList($objectType, $objectID) + { + $commiters = $this->loadModel('user')->getCommiters(); + $actions = $this->dao->select('*')->from(TABLE_ACTION) + ->where('objectType')->eq($objectType) + ->andWhere('objectID')->eq($objectID) + ->orderBy('date, id')->fetchAll('id'); + $histories = $this->getHistory(array_keys($actions)); + foreach($actions as $actionID => $action) + { + if(strtolower($action->action) == 'svncommited' and isset($commiters[$action->actor])) $action->actor = $commiters[$action->actor]; + $action->history = isset($histories[$actionID]) ? $histories[$actionID] : array(); + $actions[$actionID] = $action; + } + return $actions; + } + + /** + * Get an action record. + * + * @param int $actionID + * @access public + * @return object + */ + public function getById($actionID) + { + return $this->dao->findById((int)$actionID)->from(TABLE_ACTION)->fetch(); + } + + /** + * Get deleted objects. + * + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getTrashes($orderBy, $pager) + { + $trashes = $this->dao->select('*')->from(TABLE_ACTION) + ->where('action')->eq('deleted') + ->andWhere('extra')->eq(self::CAN_UNDELETED) + ->orderBy($orderBy)->page($pager)->fetchAll(); + if(!$trashes) return array(); + + /* Group trashes by objectType, and get there name field. */ + foreach($trashes as $object) + { + $object->objectType = str_replace('`', '', $object->objectType); + $typeTrashes[$object->objectType][] = $object->objectID; + } + foreach($typeTrashes as $objectType => $objectIds) + { + $objectIds = array_unique($objectIds); + $table = $this->config->action->objectTables[$objectType]; + $field = $this->config->action->objectNameFields[$objectType]; + $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs(); + } + + /* Add name field to the trashes. */ + foreach($trashes as $trash) $trash->objectName = $objectNames[$trash->objectType][$trash->objectID]; + return $trashes; + } + + /** + * Get histories of an action. + * + * @param int $actionID + * @access public + * @return array + */ + public function getHistory($actionID) + { + return $this->dao->select()->from(TABLE_HISTORY)->where('action')->in($actionID)->orderBy('id')->fetchGroup('action'); + } + + /** + * Log histories for an action. + * + * @param int $actionID + * @param array $changes + * @access public + * @return void + */ + public function logHistory($actionID, $changes) + { + foreach($changes as $change) + { + $change['action'] = $actionID; + $this->dao->insert(TABLE_HISTORY)->data($change)->exec(); + } + } + + /** + * Print actions of an object. + * + * @param array $action + * @access public + * @return void + */ + public function printAction($action) + { + $objectType = $action->objectType; + $actionType = strtolower($action->action); + + /** + * Set the desc string of this action. + * + * 1. If the module of this action has defined desc of this actionType, use it. + * 2. If no defined in the module language, search the common action define. + * 3. If not found in the lang->action->desc, use the $lang->action->desc->common or $lang->action->desc->extra as the default. + */ + if(isset($this->lang->$objectType->action->$actionType)) + { + $desc = $this->lang->$objectType->action->$actionType; + } + elseif(isset($this->lang->action->desc->$actionType)) + { + $desc = $this->lang->action->desc->$actionType; + } + else + { + $desc = $action->extra ? $this->lang->action->desc->extra : $this->lang->action->desc->common; + } + + /* Cycle actions, replace vars. */ + foreach($action as $key => $value) + { + if($key == 'history') continue; + + /* Desc can be an array or string. */ + if(is_array($desc)) + { + if($key == 'extra') continue; + $desc['main'] = str_replace('$' . $key, $value, $desc['main']); + } + else + { + $desc = str_replace('$' . $key, $value, $desc); + } + } + + /* If the desc is an array, process extra. Please bug/lang. */ + if(is_array($desc)) + { + $extra = strtolower($action->extra); + if(isset($desc['extra'][$extra])) + { + echo str_replace('$extra', $desc['extra'][$extra], $desc['main']); + } + else + { + echo str_replace('$extra', $action->extra, $desc['main']); + } + } + else + { + echo $desc; + } + } + + /** + * Get actions as dynamic. + * + * @param string $objectType + * @param string $count + * @param string $period + * @param string $orderBy + * @param object $pager + * @param string|int $productID all|int(like 123)|notzero all => include zeror, notzero, great than 0 + * @param string|int $projectID same as productID + * @access public + * @return array + */ + public function getDynamic($account = 'all', $period = 'all', $orderBy = 'date_desc', $pager = null, $productID = 'all', $projectID = 'all') + { + /* Computer the begin and end date of a period. */ + $period = $this->computeBeginAndEnd($period); + extract($period); + + /* Get actions. */ + $actions = $this->dao->select('*')->from(TABLE_ACTION) + ->where('date')->gt($begin) + ->andWhere('date')->lt($end) + ->beginIF($account != 'all')->andWhere('actor')->eq($account)->fi() + ->beginIF(is_numeric($productID))->andWhere('product')->like("%,$productID,%")->fi() + ->beginIF(is_numeric($projectID))->andWhere('project')->eq($projectID)->fi() + ->beginIF($productID == 'notzero')->andWhere('product')->gt(0)->fi() + ->beginIF($projectID == 'notzero')->andWhere('project')->gt(0)->fi() + ->orderBy($orderBy)->page($pager)->fetchAll(); + + if(!$actions) return array(); + return $this->transformActions($actions); + } + + /** + * Get dynamic by search. + * + * @param array $products + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getDynamicBySearch($products, $projects, $queryID, $orderBy = 'date_desc', $pager) + { + $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : ''; + + /* Get the sql and form status from the query. */ + if($query) + { + $this->session->set('actionQuery', $query->sql); + $this->session->set('actionForm', $query->form); + } + if($this->session->actionQuery == false) $this->session->set('actionQuery', ' 1 = 1'); + + $allProduct = "`product` = 'all'"; + $allProject = "`project` = 'all'"; + $actionQuery = $this->session->actionQuery; + + $productID = 0; + if(preg_match("/`product` = '(\d*)'/", $actionQuery, $out)) + { + $productID = $out[1]; + } + /* If the sql not include 'product', add check purview for product. */ + if(strpos($actionQuery, $allProduct) === false) + { + if(!in_array($productID, array_keys($products))) return array(); + } + else + { + $actionQuery = str_replace($allProduct, '1', $actionQuery); + } + + /* If the sql not include 'project', add check purview for project. */ + if(strpos($actionQuery, $allProject) === false) + { + $actionQuery = $actionQuery . 'AND `project`' . helper::dbIN(array_keys($projects)); + } + else + { + $actionQuery = str_replace($allProduct, '1', $actionQuery); + } + + $actionQuery = str_replace("`product` = '$productID'", "`product` LIKE '%,$productID,%'", $actionQuery); + + $actions = $this->getBySQL($actionQuery, $orderBy, $pager); + if(!$actions) return array(); + return $this->transformActions($actions); + } + + /** + * Get actions by SQL. + * + * @param string $sql + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getBySQL($sql, $orderBy, $pager = null) + { + return $actions = $this->dao->select('*')->from(TABLE_ACTION) + ->where($sql) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } + + /** + * Transform the actions for display. + * + * @param int $actions + * @access public + * @return void + */ + public function transformActions($actions) + { + /* Get commiters. */ + $commiters = $this->loadModel('user')->getCommiters(); + + /* Group actions by objectType, and get there name field. */ + foreach($actions as $object) $objectTypes[$object->objectType][] = $object->objectID; + foreach($objectTypes as $objectType => $objectIds) + { + if(!isset($this->config->action->objectTables[$objectType])) continue; // If no defination for this type, omit it. + + $objectIds = array_unique($objectIds); + $table = $this->config->action->objectTables[$objectType]; + $field = $this->config->action->objectNameFields[$objectType]; + if($table != '`zt_todo`') + { + $objectNames[$objectType] = $this->dao->select("id, $field AS name")->from($table)->where('id')->in($objectIds)->fetchPairs(); + } + else + { + $todos = $this->dao->select("id, $field AS name, account, private")->from($table)->where('id')->in($objectIds)->fetchAll('id'); + foreach($todos as $id => $todo) + { + if($todo->private == 1 and $todo->account != $this->app->user->account) + { + $objectNames[$objectType][$id] = $this->lang->todo->thisIsPrivate; + } + else + { + $objectNames[$objectType][$id] = $todo->name; + } + } + } + } + $objectNames['user'][0] = 'guest'; // Add guest account. + + foreach($actions as $action) + { + /* Add name field to the actions. */ + $action->objectName = isset($objectNames[$action->objectType][$action->objectID]) ? $objectNames[$action->objectType][$action->objectID] : ''; + + $actionType = strtolower($action->action); + $objectType = strtolower($action->objectType); + $action->date = date(DT_MONTHTIME2, strtotime($action->date)); + $action->actionLabel = isset($this->lang->action->label->$actionType) ? $this->lang->action->label->$actionType : $action->action; + $action->objectLabel = isset($this->lang->action->label->$objectType) ? $this->lang->action->label->$objectType : $objectType; + + /* If action type is login or logout, needn't link. */ + if($actionType == 'login' or $actionType == 'logout') + { + $action->objectLink = ''; + $action->objectLabel = ''; + continue; + } + elseif($actionType == 'svncommited') + { + $action->actor = isset($commiters[$action->actor]) ? $commiters[$action->actor] : $action->actor; + } + + /* Other actions, create a link. */ + if(strpos($action->objectLabel, '|') !== false) + { + list($objectLabel, $moduleName, $methodName, $vars) = explode('|', $action->objectLabel); + $action->objectLink = helper::createLink($moduleName, $methodName, sprintf($vars, $action->objectID)); + $action->objectLabel = $objectLabel; + } + else + { + $action->objectLink = ''; + } + } + return $actions; + } + + /** + * Compute the begin date and end date of a period. + * + * @param string $period + * @access public + * @return array + */ + public function computeBeginAndEnd($period) + { + $this->loadModel('todo'); + + $today = $this->todo->today(); + $tomorrow = $this->todo->tomorrow(); + $yesterday = $this->todo->yesterday(); + $twoDaysAgo = $this->todo->twoDaysAgo(); + + if($period == 'all') return array('begin' => '1970-1-1', 'end' => '2109-1-1'); + if($period == 'today') return array('begin' => $today, 'end' => $tomorrow); + if($period == 'yesterday') return array('begin' => $yesterday, 'end' => $today); + if($period == 'twodaysago') return array('begin' => $twoDaysAgo, 'end' => $yesterday); + + /* If the period is by week, add the end time to the end date. */ + if($period == 'thisweek' or $period == 'lastweek') + { + $func = "get$period"; + extract($this->todo->$func()); + return array('begin' => $begin, 'end' => $end . ' 23:59:59'); + } + + if($period == 'thismonth') return $this->todo->getThisMonth(); + if($period == 'lastmonth') return $this->todo->getLastMonth(); + } + + /** + * Print changes of every action. + * + * @param string $objectType + * @param array $histories + * @access public + * @return void + */ + public function printChanges($objectType, $histories) + { + if(empty($histories)) return; + + $maxLength = 0; // The max length of fields names. + $historiesWithDiff = array(); // To save histories without diff info. + $historiesWithoutDiff = array(); // To save histories with diff info. + + /* Diff histories by hasing diff info or not. Thus we can to make sure the field with diff show at last. */ + foreach($histories as $history) + { + $fieldName = $history->field; + $history->fieldLabel = isset($this->lang->$objectType->$fieldName) ? $this->lang->$objectType->$fieldName : $fieldName; + if(($length = strlen($history->fieldLabel)) > $maxLength) $maxLength = $length; + $history->diff ? $historiesWithDiff[] = $history : $historiesWithoutDiff[] = $history; + } + $histories = array_merge($historiesWithoutDiff, $historiesWithDiff); + + foreach($histories as $history) + { + $history->fieldLabel = str_pad($history->fieldLabel, $maxLength, $this->lang->action->label->space); + if($history->diff != '') + { + $history->diff = str_replace(array('', '', '', ''), array('[ins]', '[/ins]', '[del]', '[/del]'), $history->diff); + $history->diff = $history->field != 'subversion' ? htmlspecialchars($history->diff) : $history->diff; // Keep the diff link. + $history->diff = str_replace(array('[ins]', '[/ins]', '[del]', '[/del]'), array('', '', '', ''), $history->diff); + $history->diff = nl2br($history->diff); + printf($this->lang->action->desc->diff2, $history->fieldLabel, $history->diff); + } + else + { + printf($this->lang->action->desc->diff1, $history->fieldLabel, $history->old, $history->new); + } + } + } +} diff --git a/module/action/view/trash.html.php b/module/action/view/trash.html.php index 6c83be7bb2..c4ce7cc97b 100644 --- a/module/action/view/trash.html.php +++ b/module/action/view/trash.html.php @@ -1,49 +1,49 @@ - - * @package action - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - - - - -
action->objectType);?> idAB);?>action->objectName;?>action->actor);?>action->date);?>actions;?>
action->objectTypes[$action->objectType];?>objectID;?>createLink($module, 'view', "id=$action->objectID"), $action->objectName);?>actor];?>date;?>id", $lang->action->undelete, 'hiddenwin');?> -
-
action->trashTips;?>
-
show();?>
-
- + + * @package action + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + + + + +
action->objectType);?> idAB);?>action->objectName;?>action->actor);?>action->date);?>actions;?>
action->objectTypes[$action->objectType];?>objectID;?>createLink($module, 'view', "id=$action->objectID"), $action->objectName);?>actor];?>date;?>id", $lang->action->undelete, 'hiddenwin');?> +
+
action->trashTips;?>
+
show();?>
+
+ diff --git a/module/admin/control.php b/module/admin/control.php index 02e9fa1919..e37b18b0af 100644 --- a/module/admin/control.php +++ b/module/admin/control.php @@ -1,91 +1,91 @@ - - * @package admin - * @version $Id$ - * @link http://www.zentao.net - */ -class admin extends control -{ - /** - * Index page. - * @access public - * @return void - */ - public function index() - { - $user = $this->dao->select('value')->from(TABLE_CONFIG) - ->where('owner')->eq($this->app->user->account) - ->andWhere('`key`')->eq('account') - ->fetch('', false); - if($user) - { - $this->view->login = true; - $this->view->account = $user->value; - } - else - { - $this->view->login = false; - $this->view->account = ''; - } - if($this->cookie->notice == 'ignore') - { - $this->view->ignore = true; - } - else - { - $this->view->ignore = false; - } - $this->display(); - } - - /** - * Ignore notice of register and login. - * - * @access public - * @return void - */ - public function ignoreNotice() - { - setcookie('notice', 'ignore'); - die(js::locate(inlink('index'))); - } - - /** - * Register zentao. - * - * @access public - * @return void - */ - public function register() - { - if($_POST) - { - $response = $this->admin->registerByAPI(); - if($response == 'success') die(js::locate(inlink('index'), 'parent')); - } - $this->view->sn = $this->admin->getSN(); - $this->display(); - } - - /** - * Login zentao. - * - * @access public - * @return void - */ - public function login() - { - if($_POST) - { - $response = $this->admin->loginByAPI(); - if($response == 'success') die(js::locate(inlink('index'), 'parent')); - } - $this->view->sn = $this->admin->getSN(); - $this->display(); - } -} + + * @package admin + * @version $Id$ + * @link http://www.zentao.net + */ +class admin extends control +{ + /** + * Index page. + * @access public + * @return void + */ + public function index() + { + $user = $this->dao->select('value')->from(TABLE_CONFIG) + ->where('owner')->eq($this->app->user->account) + ->andWhere('`key`')->eq('account') + ->fetch('', false); + if($user) + { + $this->view->login = true; + $this->view->account = $user->value; + } + else + { + $this->view->login = false; + $this->view->account = ''; + } + if($this->cookie->notice == 'ignore') + { + $this->view->ignore = true; + } + else + { + $this->view->ignore = false; + } + $this->display(); + } + + /** + * Ignore notice of register and login. + * + * @access public + * @return void + */ + public function ignoreNotice() + { + setcookie('notice', 'ignore'); + die(js::locate(inlink('index'))); + } + + /** + * Register zentao. + * + * @access public + * @return void + */ + public function register() + { + if($_POST) + { + $response = $this->admin->registerByAPI(); + if($response == 'success') die(js::locate(inlink('index'), 'parent')); + } + $this->view->sn = $this->admin->getSN(); + $this->display(); + } + + /** + * Login zentao. + * + * @access public + * @return void + */ + public function login() + { + if($_POST) + { + $response = $this->admin->loginByAPI(); + if($response == 'success') die(js::locate(inlink('index'), 'parent')); + } + $this->view->sn = $this->admin->getSN(); + $this->display(); + } +} diff --git a/module/admin/lang/en.php b/module/admin/lang/en.php index 12f5a0d289..52fd80cc33 100644 --- a/module/admin/lang/en.php +++ b/module/admin/lang/en.php @@ -1,57 +1,57 @@ - - * @package admin - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->admin->common = 'Admin'; -$lang->admin->index = 'Index'; -$lang->admin->company = 'Company'; -$lang->admin->user = 'User'; -$lang->admin->group = 'Group'; -$lang->admin->welcome = 'Welcome to ZenTaoPMS.'; - -$lang->admin->browseCompany = 'Browse Company'; - -$lang->admin->info->caption = 'ZentaoPMS information'; -$lang->admin->info->urls = 'Related links'; -$lang->admin->info->currentVersion = 'Current version'; -$lang->admin->info->community = 'Zentao home page'; -$lang->admin->info->ask = 'Zentao ask'; -$lang->admin->info->document = 'Help document'; -$lang->admin->info->feedback = 'Feedback and suggestion'; -$lang->admin->info->faq = 'FAQ'; -$lang->admin->info->extension = 'Extension'; -$lang->admin->info->donation = 'Donation'; -$lang->admin->info->service = 'Service fee'; -$lang->admin->info->account = 'Community account'; - -$lang->admin->notice->join = "Your account is not associated with zentao community. You can %s a community account, and get 200 scores. If you have an account, just %s it with community, and you can get 150 scores."; -$lang->admin->notice->ignore = "ignore"; - -$lang->admin->register->caption = 'Register zentao community'; -$lang->admin->register->join = 'create'; -$lang->admin->register->lblAccount = 'Numbers and letters, at least three'; -$lang->admin->register->lblPasswd = 'Numbers and letters, at least six'; - -$lang->admin->register->notice->account = 'The account must be a series of letters and/or numbers, at least three'; -$lang->admin->register->notice->password = 'The password must be a series of letters and/or numbers, at least six'; -$lang->admin->register->notice->realname = 'The realname must not be empty'; -$lang->admin->register->notice->email = 'Please input your correct email address'; -$lang->admin->register->notice->notEqual = 'The password and confirm password is not equal'; -$lang->admin->register->notice->registered = 'The username has been registered'; -$lang->admin->register->notice->success = 'Register successfully'; -$lang->admin->register->notice->failed = 'Register failed'; - -$lang->admin->login->caption = 'Associated with community account'; -$lang->admin->login->join = 'associate'; - -$lang->admin->login->notice->account = 'The account must be a series of letters and/or numbers, at least three'; -$lang->admin->login->notice->password = 'The password must be a series of letters and/or numbers, at least six'; -$lang->admin->login->notice->success = 'Associate successfully'; -$lang->admin->login->notice->failed = 'Associate failed'; + + * @package admin + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->admin->common = 'Admin'; +$lang->admin->index = 'Index'; +$lang->admin->company = 'Company'; +$lang->admin->user = 'User'; +$lang->admin->group = 'Group'; +$lang->admin->welcome = 'Welcome to ZenTaoPMS.'; + +$lang->admin->browseCompany = 'Browse Company'; + +$lang->admin->info->caption = 'ZentaoPMS information'; +$lang->admin->info->urls = 'Related links'; +$lang->admin->info->currentVersion = 'Current version'; +$lang->admin->info->community = 'Zentao home page'; +$lang->admin->info->ask = 'Zentao ask'; +$lang->admin->info->document = 'Help document'; +$lang->admin->info->feedback = 'Feedback and suggestion'; +$lang->admin->info->faq = 'FAQ'; +$lang->admin->info->extension = 'Extension'; +$lang->admin->info->donation = 'Donation'; +$lang->admin->info->service = 'Service fee'; +$lang->admin->info->account = 'Community account'; + +$lang->admin->notice->join = "Your account is not associated with zentao community. You can %s a community account, and get 200 scores. If you have an account, just %s it with community, and you can get 150 scores."; +$lang->admin->notice->ignore = "ignore"; + +$lang->admin->register->caption = 'Register zentao community'; +$lang->admin->register->join = 'create'; +$lang->admin->register->lblAccount = 'Numbers and letters, at least three'; +$lang->admin->register->lblPasswd = 'Numbers and letters, at least six'; + +$lang->admin->register->notice->account = 'The account must be a series of letters and/or numbers, at least three'; +$lang->admin->register->notice->password = 'The password must be a series of letters and/or numbers, at least six'; +$lang->admin->register->notice->realname = 'The realname must not be empty'; +$lang->admin->register->notice->email = 'Please input your correct email address'; +$lang->admin->register->notice->notEqual = 'The password and confirm password is not equal'; +$lang->admin->register->notice->registered = 'The username has been registered'; +$lang->admin->register->notice->success = 'Register successfully'; +$lang->admin->register->notice->failed = 'Register failed'; + +$lang->admin->login->caption = 'Associated with community account'; +$lang->admin->login->join = 'associate'; + +$lang->admin->login->notice->account = 'The account must be a series of letters and/or numbers, at least three'; +$lang->admin->login->notice->password = 'The password must be a series of letters and/or numbers, at least six'; +$lang->admin->login->notice->success = 'Associate successfully'; +$lang->admin->login->notice->failed = 'Associate failed'; diff --git a/module/admin/lang/zh-cn.php b/module/admin/lang/zh-cn.php index 38699d9099..08cc47a385 100644 --- a/module/admin/lang/zh-cn.php +++ b/module/admin/lang/zh-cn.php @@ -1,57 +1,57 @@ - - * @package admin - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->admin->common = '后台管理'; -$lang->admin->index = '后台管理首页'; -$lang->admin->company = '公司管理'; -$lang->admin->user = '用户管理'; -$lang->admin->group = '分组管理'; -$lang->admin->welcome = '欢迎使用禅道管理软件后台管理系统'; - -$lang->admin->browseCompany = '浏览公司'; - -$lang->admin->info->caption = '禅道系统信息'; -$lang->admin->info->urls = '相关链接'; -$lang->admin->info->currentVersion = '当前版本'; -$lang->admin->info->community = '禅道主页'; -$lang->admin->info->ask = '禅道问答'; -$lang->admin->info->document = '帮助文档'; -$lang->admin->info->feedback = '反馈建议'; -$lang->admin->info->faq = '常见问题'; -$lang->admin->info->extension = '禅道插件'; -$lang->admin->info->donation = '捐助禅道'; -$lang->admin->info->service = '收费服务'; -$lang->admin->info->account = '社区账号'; - -$lang->admin->notice->join = "您的账号未关联到禅道社区,点击%s可以新建社区账号,系统赠送200积分。您还可以点击%s社区账号,系统赠送150积分。"; -$lang->admin->notice->ignore = "不再提示"; - -$lang->admin->register->caption = '注册禅道社区'; -$lang->admin->register->join = '注册'; -$lang->admin->register->lblAccount = '请设置您的用户名,英文字母和数字的组合。'; -$lang->admin->register->lblPasswd = '请设置您的密码。数字和字母的组合,六位以上。'; - -$lang->admin->register->notice->account = '用户名必须是数字和字母组合,三位以上'; -$lang->admin->register->notice->password = '密码必须是数字和字母组合,六位以上'; -$lang->admin->register->notice->realname = '真实姓名不能为空'; -$lang->admin->register->notice->email = '请填写正确的邮箱地址'; -$lang->admin->register->notice->notEqual = '密码和确认密码不相等'; -$lang->admin->register->notice->registered = '用户名已注册'; -$lang->admin->register->notice->success = '注册成功'; -$lang->admin->register->notice->failed = '注册失败'; - -$lang->admin->login->caption = '关联社区账号'; -$lang->admin->login->join = '关联'; - -$lang->admin->login->notice->account = '用户名必须是数字和字母组合,三位以上'; -$lang->admin->login->notice->password = '密码必须是数字和字母组合,六位以上'; -$lang->admin->login->notice->success = '关联账户成功'; -$lang->admin->login->notice->failed = '关联账户失败'; + + * @package admin + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->admin->common = '后台管理'; +$lang->admin->index = '后台管理首页'; +$lang->admin->company = '公司管理'; +$lang->admin->user = '用户管理'; +$lang->admin->group = '分组管理'; +$lang->admin->welcome = '欢迎使用禅道管理软件后台管理系统'; + +$lang->admin->browseCompany = '浏览公司'; + +$lang->admin->info->caption = '禅道系统信息'; +$lang->admin->info->urls = '相关链接'; +$lang->admin->info->currentVersion = '当前版本'; +$lang->admin->info->community = '禅道主页'; +$lang->admin->info->ask = '禅道问答'; +$lang->admin->info->document = '帮助文档'; +$lang->admin->info->feedback = '反馈建议'; +$lang->admin->info->faq = '常见问题'; +$lang->admin->info->extension = '禅道插件'; +$lang->admin->info->donation = '捐助禅道'; +$lang->admin->info->service = '收费服务'; +$lang->admin->info->account = '社区账号'; + +$lang->admin->notice->join = "您的账号未关联到禅道社区,点击%s可以新建社区账号,系统赠送200积分。您还可以点击%s社区账号,系统赠送150积分。"; +$lang->admin->notice->ignore = "不再提示"; + +$lang->admin->register->caption = '注册禅道社区'; +$lang->admin->register->join = '注册'; +$lang->admin->register->lblAccount = '请设置您的用户名,英文字母和数字的组合。'; +$lang->admin->register->lblPasswd = '请设置您的密码。数字和字母的组合,六位以上。'; + +$lang->admin->register->notice->account = '用户名必须是数字和字母组合,三位以上'; +$lang->admin->register->notice->password = '密码必须是数字和字母组合,六位以上'; +$lang->admin->register->notice->realname = '真实姓名不能为空'; +$lang->admin->register->notice->email = '请填写正确的邮箱地址'; +$lang->admin->register->notice->notEqual = '密码和确认密码不相等'; +$lang->admin->register->notice->registered = '用户名已注册'; +$lang->admin->register->notice->success = '注册成功'; +$lang->admin->register->notice->failed = '注册失败'; + +$lang->admin->login->caption = '关联社区账号'; +$lang->admin->login->join = '关联'; + +$lang->admin->login->notice->account = '用户名必须是数字和字母组合,三位以上'; +$lang->admin->login->notice->password = '密码必须是数字和字母组合,六位以上'; +$lang->admin->login->notice->success = '关联账户成功'; +$lang->admin->login->notice->failed = '关联账户失败'; diff --git a/module/admin/lang/zh-tw.php b/module/admin/lang/zh-tw.php index c6a875d315..cde776246b 100644 --- a/module/admin/lang/zh-tw.php +++ b/module/admin/lang/zh-tw.php @@ -1,57 +1,57 @@ - - * @package admin - * @version $Id: zh-tw.php 2594 2012-02-20 09:06:53Z zhujinyonging@gmail.com $ - * @link http://www.zentao.net - */ -$lang->admin->common = '後台管理'; -$lang->admin->index = '後台管理首頁'; -$lang->admin->company = '公司管理'; -$lang->admin->user = '用戶管理'; -$lang->admin->group = '分組管理'; -$lang->admin->welcome = '歡迎使用禪道管理軟件後台管理系統'; - -$lang->admin->browseCompany = '瀏覽公司'; - -$lang->admin->info->caption = '禪道系統信息'; -$lang->admin->info->urls = '相關連結'; -$lang->admin->info->currentVersion = '當前版本'; -$lang->admin->info->community = '禪道主頁'; -$lang->admin->info->ask = '禪道問答'; -$lang->admin->info->document = '幫助文檔'; -$lang->admin->info->feedback = '反饋建議'; -$lang->admin->info->faq = '常見問題'; -$lang->admin->info->extension = '禪道插件'; -$lang->admin->info->donation = '捐助禪道'; -$lang->admin->info->service = '收費服務'; -$lang->admin->info->account = '社區賬號'; - -$lang->admin->notice->join = "您的賬號未關聯到禪道社區,點擊%s可以新建社區賬號,系統贈送200積分。您還可以點擊%s社區賬號,系統贈送150積分。"; -$lang->admin->notice->ignore = "不再提示"; - -$lang->admin->register->caption = '註冊禪道社區'; -$lang->admin->register->join = '註冊'; -$lang->admin->register->lblAccount = '請設置您的用戶名,英文字母和數字的組合。'; -$lang->admin->register->lblPasswd = '請設置您的密碼。數字和字母的組合,六位以上。'; - -$lang->admin->register->notice->account = '用戶名必須是數字和字母組合,三位以上'; -$lang->admin->register->notice->password = '密碼必須是數字和字母組合,六位以上'; -$lang->admin->register->notice->realname = '真實姓名不能為空'; -$lang->admin->register->notice->email = '請填寫正確的郵箱地址'; -$lang->admin->register->notice->notEqual = '密碼和確認密碼不相等'; -$lang->admin->register->notice->registered = '用戶名已註冊'; -$lang->admin->register->notice->success = '註冊成功'; -$lang->admin->register->notice->failed = '註冊失敗'; - -$lang->admin->login->caption = '關聯社區賬號'; -$lang->admin->login->join = '關聯'; - -$lang->admin->login->notice->account = '用戶名必須是數字和字母組合,三位以上'; -$lang->admin->login->notice->password = '密碼必須是數字和字母組合,六位以上'; -$lang->admin->login->notice->success = '關聯賬戶成功'; -$lang->admin->login->notice->failed = '關聯賬戶失敗'; + + * @package admin + * @version $Id: zh-tw.php 2594 2012-02-20 09:06:53Z zhujinyonging@gmail.com $ + * @link http://www.zentao.net + */ +$lang->admin->common = '後台管理'; +$lang->admin->index = '後台管理首頁'; +$lang->admin->company = '公司管理'; +$lang->admin->user = '用戶管理'; +$lang->admin->group = '分組管理'; +$lang->admin->welcome = '歡迎使用禪道管理軟件後台管理系統'; + +$lang->admin->browseCompany = '瀏覽公司'; + +$lang->admin->info->caption = '禪道系統信息'; +$lang->admin->info->urls = '相關連結'; +$lang->admin->info->currentVersion = '當前版本'; +$lang->admin->info->community = '禪道主頁'; +$lang->admin->info->ask = '禪道問答'; +$lang->admin->info->document = '幫助文檔'; +$lang->admin->info->feedback = '反饋建議'; +$lang->admin->info->faq = '常見問題'; +$lang->admin->info->extension = '禪道插件'; +$lang->admin->info->donation = '捐助禪道'; +$lang->admin->info->service = '收費服務'; +$lang->admin->info->account = '社區賬號'; + +$lang->admin->notice->join = "您的賬號未關聯到禪道社區,點擊%s可以新建社區賬號,系統贈送200積分。您還可以點擊%s社區賬號,系統贈送150積分。"; +$lang->admin->notice->ignore = "不再提示"; + +$lang->admin->register->caption = '註冊禪道社區'; +$lang->admin->register->join = '註冊'; +$lang->admin->register->lblAccount = '請設置您的用戶名,英文字母和數字的組合。'; +$lang->admin->register->lblPasswd = '請設置您的密碼。數字和字母的組合,六位以上。'; + +$lang->admin->register->notice->account = '用戶名必須是數字和字母組合,三位以上'; +$lang->admin->register->notice->password = '密碼必須是數字和字母組合,六位以上'; +$lang->admin->register->notice->realname = '真實姓名不能為空'; +$lang->admin->register->notice->email = '請填寫正確的郵箱地址'; +$lang->admin->register->notice->notEqual = '密碼和確認密碼不相等'; +$lang->admin->register->notice->registered = '用戶名已註冊'; +$lang->admin->register->notice->success = '註冊成功'; +$lang->admin->register->notice->failed = '註冊失敗'; + +$lang->admin->login->caption = '關聯社區賬號'; +$lang->admin->login->join = '關聯'; + +$lang->admin->login->notice->account = '用戶名必須是數字和字母組合,三位以上'; +$lang->admin->login->notice->password = '密碼必須是數字和字母組合,六位以上'; +$lang->admin->login->notice->success = '關聯賬戶成功'; +$lang->admin->login->notice->failed = '關聯賬戶失敗'; diff --git a/module/admin/model.php b/module/admin/model.php index 900a75691d..82b9bd34a3 100644 --- a/module/admin/model.php +++ b/module/admin/model.php @@ -1,207 +1,207 @@ - - * @package admin - * @version $Id$ - * @link http://www.zentao.net - */ -?> -setAgent(); - } - - /** - * Set the api agent. - * - * @access public - * @return void - */ - public function setAgent() - { - $this->agent = $this->app->loadClass('snoopy'); - } - - /** - * Post data form API - * - * @param string $url - * @param string $formvars - * @access public - * @return void - */ - public function postAPI($url, $formvars = "") - { - $this->agent->submit($url, $formvars); - return $this->agent->results; - } - - /** - * Get status of zentaopms. - * - * @access public - * @return void - */ - public function getStatOfPMS() - { - $sql = "SHOW TABLE STATUS"; - $tables = $this->dbh->query($sql)->fetchALL(); - } - - /** - * Get state of company. - * - * @param int $companyID - * @access public - * @return void - */ - public function getStatOfCompany($companyID) - { - } - - /** - * Get system info. - * - * @access public - * @return void - */ - public function getStatOfSys() - { - - } - - /** - * Register zentao by API. - * - * @access public - * @return void - */ - public function registerByAPI() - { - $data = urlencode(json_encode($_POST)); - $apiURL = 'http://www.zentao.net/user-apiRegister.html'; - $response = $this->postAPI($apiURL, $data); - switch($response) - { - case 'success': - $this->dao->insert(TABLE_CONFIG) - ->set('owner')->eq($this->app->user->account) - ->set('`key`')->eq('account') - ->set('section')->eq('global') - ->set('value')->eq($this->post->account) - ->exec(false); - echo js::alert($this->lang->admin->register->notice->success); - break; - case 'failed': - echo js::alert($this->lang->admin->register->notice->failed); - break; - case 'userError': - echo js::alert($this->lang->admin->register->notice->account); - break; - case 'passwordError': - echo js::alert($this->lang->admin->register->notice->password); - break; - case 'realnameError': - echo js::alert($this->lang->admin->register->notice->realname); - break; - case 'emailError': - echo js::alert($this->lang->admin->register->notice->email); - break; - case 'notEqual': - echo js::alert($this->lang->admin->register->notice->notEqual); - break; - case 'registered': - echo js::alert($this->lang->admin->register->notice->registered); - break; - default: - echo js::alert($this->lang->admin->register->notice->failed); - } - return $response; - } - - /** - * Login zentao by API. - * - * @access public - * @return void - */ - public function loginByAPI() - { - $data = urlencode(json_encode($_POST)); - $apiURL = 'http://www.zentao.net/user-apiLogin.html'; - $response = $this->postAPI($apiURL, $data); - switch($response) - { - case 'success': - $this->dao->insert(TABLE_CONFIG) - ->set('owner')->eq($this->app->user->account) - ->set('`key`')->eq('account') - ->set('section')->eq('global') - ->set('value')->eq($this->post->account) - ->exec(false); - echo js::alert($this->lang->admin->login->notice->success); - break; - case 'userError': - echo js::alert($this->lang->admin->login->notice->account); - break; - case 'passwordError': - echo js::alert($this->lang->admin->login->notice->password); - break; - case 'failed': - echo js::alert($this->lang->admin->login->notice->failed); - break; - default: - echo js::alert($this->lang->admin->login->notice->failed); - } - return $response; - } - - /** - * Get pms sn. - * - * @access public - * @return void - */ - public function getSN() - { - $sn = $this->dao->select('value')->from(TABLE_CONFIG)->where('`key`')->eq('sn')->fetch('', false); - if($sn) - { - return $sn->value; - } - else - { - return ''; - } - } -} + + * @package admin + * @version $Id$ + * @link http://www.zentao.net + */ +?> +setAgent(); + } + + /** + * Set the api agent. + * + * @access public + * @return void + */ + public function setAgent() + { + $this->agent = $this->app->loadClass('snoopy'); + } + + /** + * Post data form API + * + * @param string $url + * @param string $formvars + * @access public + * @return void + */ + public function postAPI($url, $formvars = "") + { + $this->agent->submit($url, $formvars); + return $this->agent->results; + } + + /** + * Get status of zentaopms. + * + * @access public + * @return void + */ + public function getStatOfPMS() + { + $sql = "SHOW TABLE STATUS"; + $tables = $this->dbh->query($sql)->fetchALL(); + } + + /** + * Get state of company. + * + * @param int $companyID + * @access public + * @return void + */ + public function getStatOfCompany($companyID) + { + } + + /** + * Get system info. + * + * @access public + * @return void + */ + public function getStatOfSys() + { + + } + + /** + * Register zentao by API. + * + * @access public + * @return void + */ + public function registerByAPI() + { + $data = urlencode(json_encode($_POST)); + $apiURL = 'http://www.zentao.net/user-apiRegister.html'; + $response = $this->postAPI($apiURL, $data); + switch($response) + { + case 'success': + $this->dao->insert(TABLE_CONFIG) + ->set('owner')->eq($this->app->user->account) + ->set('`key`')->eq('account') + ->set('section')->eq('global') + ->set('value')->eq($this->post->account) + ->exec(false); + echo js::alert($this->lang->admin->register->notice->success); + break; + case 'failed': + echo js::alert($this->lang->admin->register->notice->failed); + break; + case 'userError': + echo js::alert($this->lang->admin->register->notice->account); + break; + case 'passwordError': + echo js::alert($this->lang->admin->register->notice->password); + break; + case 'realnameError': + echo js::alert($this->lang->admin->register->notice->realname); + break; + case 'emailError': + echo js::alert($this->lang->admin->register->notice->email); + break; + case 'notEqual': + echo js::alert($this->lang->admin->register->notice->notEqual); + break; + case 'registered': + echo js::alert($this->lang->admin->register->notice->registered); + break; + default: + echo js::alert($this->lang->admin->register->notice->failed); + } + return $response; + } + + /** + * Login zentao by API. + * + * @access public + * @return void + */ + public function loginByAPI() + { + $data = urlencode(json_encode($_POST)); + $apiURL = 'http://www.zentao.net/user-apiLogin.html'; + $response = $this->postAPI($apiURL, $data); + switch($response) + { + case 'success': + $this->dao->insert(TABLE_CONFIG) + ->set('owner')->eq($this->app->user->account) + ->set('`key`')->eq('account') + ->set('section')->eq('global') + ->set('value')->eq($this->post->account) + ->exec(false); + echo js::alert($this->lang->admin->login->notice->success); + break; + case 'userError': + echo js::alert($this->lang->admin->login->notice->account); + break; + case 'passwordError': + echo js::alert($this->lang->admin->login->notice->password); + break; + case 'failed': + echo js::alert($this->lang->admin->login->notice->failed); + break; + default: + echo js::alert($this->lang->admin->login->notice->failed); + } + return $response; + } + + /** + * Get pms sn. + * + * @access public + * @return void + */ + public function getSN() + { + $sn = $this->dao->select('value')->from(TABLE_CONFIG)->where('`key`')->eq('sn')->fetch('', false); + if($sn) + { + return $sn->value; + } + else + { + return ''; + } + } +} diff --git a/module/admin/view/browsecompany.html.php b/module/admin/view/browsecompany.html.php index 1e41fc2eea..643096fc46 100644 --- a/module/admin/view/browsecompany.html.php +++ b/module/admin/view/browsecompany.html.php @@ -1,47 +1,47 @@ - - * @package admin - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
company->id;?>company->name;?>company->phone;?>company->fax;?>company->address;?>company->zipcode;?>company->website;?>company->backyard;?>company->pms;?>company->guest;?>actions;?>
id;?>name;?>phone;?>fax;?>address;?>zipcode;?>website, $company->website, '_blank');?>backyard,$company->backyard, '_blank');?>pms, $company->pms, '_blank');?>company->guestList[(int)$company->guest];?> - createLink('company', 'edit', "companyID=$company->id"), $this->lang->company->edit);?> - createLink('company', 'delete', "companyID=$company->id"), $this->lang->company->delete, "hiddenwin");?> -
- + + * @package admin + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
company->id;?>company->name;?>company->phone;?>company->fax;?>company->address;?>company->zipcode;?>company->website;?>company->backyard;?>company->pms;?>company->guest;?>actions;?>
id;?>name;?>phone;?>fax;?>address;?>zipcode;?>website, $company->website, '_blank');?>backyard,$company->backyard, '_blank');?>pms, $company->pms, '_blank');?>company->guestList[(int)$company->guest];?> + createLink('company', 'edit', "companyID=$company->id"), $this->lang->company->edit);?> + createLink('company', 'delete', "companyID=$company->id"), $this->lang->company->delete, "hiddenwin");?> +
+ diff --git a/module/api/control.php b/module/api/control.php index 278278693a..bf3a050b00 100644 --- a/module/api/control.php +++ b/module/api/control.php @@ -1,50 +1,50 @@ - - * @package api - * @version $Id$ - * @link http://www.zentao.net - */ -class api extends control -{ - /** - * Return session to the client. - * - * @access public - * @return void - */ - public function getSessionID() - { - $this->session->set('rand', mt_rand(0, 10000)); - $this->view->sessionName = session_name(); - $this->view->sessionID = session_id(); - $this->view->rand = $this->session->rand; - $this->display(); - } - - /** - * Execute a module's model's method, return the result. - * - * @param string $moduleName - * @param string $methodName - * @param string $params param1=value1,param2=value2, don't use & to join them. - * @access public - * @return string - */ - public function getModel($moduleName, $methodName, $params = '') - { - parse_str(str_replace(',', '&', $params), $params); - $module = $this->loadModel($moduleName); - $result = call_user_func_array(array(&$module, $methodName), $params); - if(dao::isError()) die(json_encode(dao::getError())); - $output['status'] = $result ? 'success' : 'fail'; - $output['data'] = json_encode($result); - $output['md5'] = md5($output['data']); - $this->output = json_encode($output); - die($this->output); - } -} + + * @package api + * @version $Id$ + * @link http://www.zentao.net + */ +class api extends control +{ + /** + * Return session to the client. + * + * @access public + * @return void + */ + public function getSessionID() + { + $this->session->set('rand', mt_rand(0, 10000)); + $this->view->sessionName = session_name(); + $this->view->sessionID = session_id(); + $this->view->rand = $this->session->rand; + $this->display(); + } + + /** + * Execute a module's model's method, return the result. + * + * @param string $moduleName + * @param string $methodName + * @param string $params param1=value1,param2=value2, don't use & to join them. + * @access public + * @return string + */ + public function getModel($moduleName, $methodName, $params = '') + { + parse_str(str_replace(',', '&', $params), $params); + $module = $this->loadModel($moduleName); + $result = call_user_func_array(array(&$module, $methodName), $params); + if(dao::isError()) die(json_encode(dao::getError())); + $output['status'] = $result ? 'success' : 'fail'; + $output['data'] = json_encode($result); + $output['md5'] = md5($output['data']); + $this->output = json_encode($output); + die($this->output); + } +} diff --git a/module/api/lang/en.php b/module/api/lang/en.php index 59555de28f..db326bc1a1 100644 --- a/module/api/lang/en.php +++ b/module/api/lang/en.php @@ -1,13 +1,13 @@ - - * @package api - * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $ - * @link http://www.zentao.net - */ -$lang->api->common = 'API'; -$lang->api->getModel = 'Super Model API'; + + * @package api + * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $ + * @link http://www.zentao.net + */ +$lang->api->common = 'API'; +$lang->api->getModel = 'Super Model API'; diff --git a/module/api/lang/zh-cn.php b/module/api/lang/zh-cn.php index e18a454d8d..eca46bcd28 100644 --- a/module/api/lang/zh-cn.php +++ b/module/api/lang/zh-cn.php @@ -1,13 +1,13 @@ - - * @package api - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->api->common = 'API接口'; -$lang->api->getModel = '超级model调用接口'; + + * @package api + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->api->common = 'API接口'; +$lang->api->getModel = '超级model调用接口'; diff --git a/module/api/lang/zh-tw.php b/module/api/lang/zh-tw.php index b6fbf83b71..7156ff4889 100644 --- a/module/api/lang/zh-tw.php +++ b/module/api/lang/zh-tw.php @@ -1,13 +1,13 @@ - - * @package api - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->api->common = 'API介面'; -$lang->api->getModel = '超級model調用介面'; + + * @package api + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->api->common = 'API介面'; +$lang->api->getModel = '超級model調用介面'; diff --git a/module/api/model.php b/module/api/model.php index 6b6ff00676..7b5d114ffe 100644 --- a/module/api/model.php +++ b/module/api/model.php @@ -1,15 +1,15 @@ - - * @package api - * @version $Id$ - * @link http://www.zentao.net - */ -class apiModel extends model -{ -} - + + * @package api + * @version $Id$ + * @link http://www.zentao.net + */ +class apiModel extends model +{ +} + diff --git a/module/bug/control.php b/module/bug/control.php index 78b439750f..b23358799a 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -1,947 +1,947 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -class bug extends control -{ - private $products = array(); - - /** - * Construct function, load some modules auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('product'); - $this->loadModel('tree'); - $this->loadModel('user'); - $this->loadModel('action'); - $this->loadModel('story'); - $this->loadModel('task'); - $this->products = $this->product->getPairs(); - if(empty($this->products)) - { - echo js::alert($this->lang->product->errorNoProduct); - die(js::locate($this->createLink('product', 'create'))); - } - $this->view->products = $this->products; - } - - /** - * The index page, locate to browse. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('bug', 'browse')); - } - - /** - * Browse bugs. - * - * @param int $productID - * @param string $browseType - * @param int $param - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Set browseType, productID, moduleID and queryID. */ - $browseType = strtolower($browseType); - $productID = $this->product->saveState($productID, $this->products); - $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Set menu and save session. */ - $this->bug->setMenu($this->products, $productID); - $this->session->set('bugList', $this->app->getURI(true)); - - /* Process the order by field. */ - if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc'; - setcookie('qaBugOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - $projects = $this->loadModel('project')->getPairs(); - $projects[0] = ''; - - /* Get bugs. */ - $bugs = array(); - if($browseType == 'all') $bugs = $this->bug->getAllBugs($productID, $projects, $orderBy, $pager); - elseif($browseType == "bymodule") - { - $childModuleIds = $this->tree->getAllChildId($moduleID); - $bugs = $this->bug->getModuleBugs($productID, $childModuleIds, $projects, $orderBy, $pager); - } - elseif($browseType == 'assigntome') $bugs = $this->bug->getByAssigntome($productID, $projects, $orderBy, $pager); - elseif($browseType == 'openedbyme') $bugs = $this->bug->getByOpenedbyme($productID, $projects, $orderBy, $pager); - elseif($browseType == 'resolvedbyme') $bugs = $this->bug->getByResolvedbyme($productID, $projects, $orderBy, $pager); - elseif($browseType == 'assigntonull') $bugs = $this->bug->getByAssigntonull($productID, $projects, $orderBy, $pager); - elseif($browseType == 'unresolved') $bugs = $this->bug->getByStatus($productID, $projects, 'unresolved', $orderBy, $pager); - elseif($browseType == 'unclosed') $bugs = $this->bug->getByStatus($productID, $projects, 'unclosed', $orderBy, $pager); - elseif($browseType == 'longlifebugs') $bugs = $this->bug->getByLonglifebugs($productID, $projects, $orderBy, $pager); - elseif($browseType == 'postponedbugs') $bugs = $this->bug->getByPostponedbugs($productID, $projects, $orderBy, $pager); - elseif($browseType == 'needconfirm') $bugs = $this->bug->getByNeedconfirm($productID, $projects, $orderBy, $pager); - elseif($browseType == 'bysearch') $bugs = $this->bug->getBySearch($productID, $projects, $queryID, $orderBy, $pager); - - /* Process the sql, get the conditon partion, save it to session. Thus the report page can use the same condition. */ - if($browseType != 'needconfirm') - { - $sql = explode('WHERE', $this->dao->get()); - $sql = explode('ORDER', $sql[1]); - $this->session->set('bugReportCondition', $sql[0]); - } - - /* Get custom fields. */ - $customFields = $this->cookie->bugFields != false ? $this->cookie->bugFields : $this->config->bug->list->defaultFields; - $customed = !($customFields == $this->config->bug->list->defaultFields); - - /* If customed, get related name or titles. */ - if($customed) $bugs = $this->bug->formCustomedBugs($bugs); - - /* Build the search form. */ - $this->config->bug->search['actionURL'] = $this->createLink('bug', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); - $this->config->bug->search['queryID'] = $queryID; - $this->config->bug->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->bug->allProduct); - $this->config->bug->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); - $this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID); - $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID); - $this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getProductBuildPairs($productID); - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search); - - $users = $this->user->getPairs('noletter'); - - $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common; - $position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $position[] = $this->lang->bug->common; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'bug', $startModuleID = 0, array('treeModel', 'createBugLink')); - $this->view->browseType = $browseType; - $this->view->bugs = $bugs; - $this->view->users = $users; - $this->view->pager = $pager; - $this->view->param = $param; - $this->view->orderBy = $orderBy; - $this->view->moduleID = $moduleID; - $this->view->customed = $customed; - $this->view->customFields= explode(',', str_replace(' ', '', trim($customFields))); - $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; - - $this->display(); - } - - /** - * The report page. - * - * @param int $productID - * @param string $browseType - * @param int $moduleID - * @access public - * @return void - */ - public function report($productID, $browseType, $moduleID) - { - $this->loadModel('report'); - $this->view->charts = array(); - $this->view->renderJS = ''; - - if(!empty($_POST)) - { - foreach($this->post->charts as $chart) - { - $chartFunc = 'getDataOf' . $chart; - $chartData = $this->bug->$chartFunc(); - $chartOption = $this->lang->bug->report->$chart; - $this->bug->mergeChartOption($chart); - - $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); - $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); - $this->view->datas[$chart] = $this->report->computePercent($chartData); - } - $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); - } - - $this->bug->setMenu($this->products, $productID); - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common; - $this->view->productID = $productID; - $this->view->browseType = $browseType; - $this->view->moduleID = $moduleID; - $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; - $this->display(); - } - - /** - * Create a bug. - * - * @param int $productID - * @param string $extras others params, forexample, projectID=10,moduleID=10 - * @access public - * @return void - */ - public function create($productID, $extras = '') - { - $this->view->users = $this->user->getPairs('nodeleted'); - if(empty($this->products)) $this->locate($this->createLink('product', 'create')); - - if(!empty($_POST)) - { - $bugID = $this->bug->create(); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('bug', $bugID, 'Opened'); - $this->sendmail($bugID, $actionID); - die(js::locate($this->createLink('bug', 'browse', "productID={$this->post->product}&type=byModule¶m={$this->post->module}"), 'parent')); - } - - /* Get product, then set menu. */ - $productID = $this->product->saveState($productID, $this->products); - $this->bug->setMenu($this->products, $productID); - - /* Remove the unused types. */ - unset($this->lang->bug->typeList['designchange']); - unset($this->lang->bug->typeList['newfeature']); - unset($this->lang->bug->typeList['trackthings']); - - /* Init vars. */ - $moduleID = 0; - $projectID = 0; - $taskID = 0; - $storyID = 0; - $buildID = 0; - $caseID = 0; - $runID = 0; - $title = ''; - $steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect; - $os = ''; - $browser = ''; - $assignedTo = ''; - $mailto = ''; - $keywords = ''; - $severity = 3; - $type = 'codeerror'; - - /* Parse the extras. */ - $extras = str_replace(array(',', ' '), array('&', ''), $extras); - parse_str($extras); - - /* If set runID, get the last result info as the template. */ - if($runID > 0) $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->limit(1)->fetch('id'); - if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID)); - - /* If set caseID and runID='', get the last result info as the template. */ - if($caseID > 0 && $runID == '') - { - $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('date desc')->limit(1)->fetch('id'); - if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID, $caseID, $version)); - } - - /* If bugID setted, use this bug as template. */ - if(isset($bugID)) - { - $bug = $this->bug->getById($bugID); - extract((array)$bug); - $projectID = $bug->project; - $moduleID = $bug->module; - $taskID = $bug->task; - $storyID = $bug->story; - $buildID = $bug->openedBuild; - $severity = $bug->severity; - $type = $bug->type; - } - - /* If projectID is setted, get builds and stories of this project. */ - if($projectID) - { - $builds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty'); - $stories = $this->story->getProjectStoryPairs($projectID); - } - else - { - $builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); - $stories = $this->story->getProductStoryPairs($productID); - } - - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->create; - - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); - $this->view->stories = $stories; - $this->view->projects = $this->product->getProjectPairs($productID, $params = 'nodeleted'); - $this->view->builds = $builds; - $this->view->tasks = $this->loadModel('task')->getProjectTaskPairs($projectID); - $this->view->moduleID = $moduleID; - $this->view->projectID = $projectID; - $this->view->taskID = $taskID; - $this->view->storyID = $storyID; - $this->view->buildID = $buildID; - $this->view->caseID = $caseID; - $this->view->title = $title; - $this->view->steps = htmlspecialchars($steps); - $this->view->os = $os; - $this->view->browser = $browser; - $this->view->assignedTo = $assignedTo; - $this->view->mailto = $mailto; - $this->view->keywords = $keywords; - $this->view->severity = $severity; - $this->view->type = $type; - - $this->display(); - } - - /** - * View a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function view($bugID) - { - /* Judge bug exits or not. */ - $bug = $this->bug->getById($bugID); - if(!$bug) die(js::error($this->lang->notFound) . js::locate('back')); - - /* Set menu. */ - $this->bug->setMenu($this->products, $bug->product); - - /* Get product info. */ - $productID = $bug->product; - $productName = $this->products[$productID]; - - /* Header and positon. */ - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->view; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName); - $this->view->position[] = $this->lang->bug->view; - - /* Assign. */ - $this->view->productID = $productID; - $this->view->productName = $productName; - $this->view->modulePath = $this->tree->getParents($bug->module); - $this->view->bug = $bug; - $this->view->users = $this->user->getPairs('noletter'); - $this->view->actions = $this->action->getList('bug', $bugID); - $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); - - $this->display(); - } - - /** - * Edit a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function edit($bugID, $comment = false) - { - if(!empty($_POST)) - { - $changes = array(); - $files = array(); - if($comment == false) - { - $changes = $this->bug->update($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $files = $this->loadModel('file')->saveUpload('bug', $bugID); - } - if($this->post->comment != '' or !empty($changes) or !empty($files)) - { - $action = !empty($changes) ? 'Edited' : 'Commented'; - $fileAction = ''; - if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; - $actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($bugID, $actionID); - } - - $bug = $this->bug->getById($bugID); - if($bug->toTask != 0) - { - foreach($changes as $change) - { - if($change['field'] == 'status') - { - $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); - $cancelURL = $this->server->HTTP_REFERER; - die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent')); - } - } - } - die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); - } - - /* Get the info of bug, current product and modue. */ - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $projectID = $bug->project; - $currentModuleID = $bug->module; - - /** - * Remove designchange, newfeature, trackings from the typeList, because should be tracked in story or task. - * These thress types if upgrade from bugfree2.x. - */ - if($bug->type != 'designchange') unset($this->lang->bug->typeList['designchange']); - if($bug->type != 'newfeature') unset($this->lang->bug->typeList['newfeature']); - if($bug->type != 'trackthings') unset($this->lang->bug->typeList['trackthings']); - - /* Set the menu. */ - $this->bug->setMenu($this->products, $productID); - - /* Set header and position. */ - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->edit; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->edit; - - /* Assign. */ - if($projectID) - { - $this->view->openedBuilds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty'); - } - else - { - $this->view->openedBuilds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); - } - $this->view->bug = $bug; - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); - $this->view->currentModuleID = $currentModuleID; - $this->view->projects = $this->product->getProjectPairs($bug->product); - $this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product); - $this->view->tasks = $this->task->getProjectTaskPairs($bug->project); - $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy"); - $this->view->resolvedBuilds = array('' => '') + $this->view->openedBuilds; - $this->view->actions = $this->action->getList('bug', $bugID); - $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account); - - $this->display(); - } - - /** - * confirm a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function confirmBug($bugID) - { - if(!empty($_POST)) - { - $this->bug->confirm($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('bug', $bugID, 'bugConfirmed', $this->post->comment); - $this->sendmail($bugID, $actionID); - die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); - } - - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $this->bug->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->confirmBug; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->confirmBug; - - $this->view->bug = $bug; - $this->view->actions = $this->action->getList('bug', $bugID); - $this->display(); - } - - /** - * Resolve a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function resolve($bugID) - { - $this->view->users = $this->user->getPairs('nodeleted'); - - if(!empty($_POST)) - { - $this->bug->resolve($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('bug', $bugID, 'Resolved', $this->post->comment, $this->post->resolution); - $this->sendmail($bugID, $actionID); - - $bug = $this->bug->getById($bugID); - if($bug->toTask != 0) - { - $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); - $cancelURL = $this->createLink('bug', 'view', "bugID=$bugID"); - die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent')); - } - die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); - } - - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $this->bug->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->resolve; - - $this->view->bug = $bug; - $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); - $this->view->actions = $this->action->getList('bug', $bugID); - $this->display(); - } - - /** - * Activate a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function activate($bugID) - { - $this->view->users = $this->user->getPairs('nodeleted'); - - if(!empty($_POST)) - { - $this->bug->activate($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $files = $this->loadModel('file')->saveUpload('bug', $bugID); - $actionID = $this->action->create('bug', $bugID, 'Activated', $this->post->comment); - $this->sendmail($bugID, $actionID); - die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); - } - - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $this->bug->setMenu($this->products, $productID); - - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->activate; - - $this->view->bug = $bug; - $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); - $this->view->actions = $this->action->getList('bug', $bugID); - - $this->display(); - } - - /** - * Close a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function close($bugID) - { - $this->view->users = $this->user->getPairs('noletter'); - if(!empty($_POST)) - { - $this->bug->close($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment); - $this->sendmail($bugID, $actionID); - die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); - } - - $bug = $this->bug->getById($bugID); - $productID = $bug->product; - $this->bug->setMenu($this->products, $productID); - - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->close; - $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->bug->close; - - $this->view->bug = $bug; - $this->view->actions = $this->action->getList('bug', $bugID); - $this->display(); - } - - /** - * Confirm story change. - * - * @param int $bugID - * @access public - * @return void - */ - public function confirmStoryChange($bugID) - { - $bug = $this->bug->getById($bugID); - $this->dao->update(TABLE_BUG)->set('storyVersion')->eq($bug->latestStoryVersion)->where('id')->eq($bugID)->exec(); - $this->loadModel('action')->create('bug', $bugID, 'confirmed', '', $bug->latestStoryVersion); - die(js::reload('parent')); - } - - /** - * Delete a bug. - * - * @param int $bugID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($bugID, $confirm = 'no') - { - $bug = $this->bug->getById($bugID); - if($confirm == 'no') - { - die(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes"))); - } - else - { - $this->bug->delete(TABLE_BUG, $bugID); - if($bug->toTask != 0) echo js::alert($this->lang->bug->remindTask . $bug->toTask); - die(js::locate($this->session->bugList, 'parent')); - } - } - - /** - * Save current template. - * - * @access public - * @return string - */ - public function saveTemplate() - { - $this->bug->saveUserBugTemplate(); - if(dao::isError()) die(js::error(dao::getError())); - die($this->fetch('bug', 'buildTemplates')); - } - - /** - * Build the user templates selection code. - * - * @access public - * @return void - */ - public function buildTemplates() - { - $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account); - $this->display('bug', 'buildTemplates'); - } - - /** - * Delete a user template. - * - * @param int $templateID - * @access public - * @return void - */ - public function deleteTemplate($templateID) - { - $this->dao->delete()->from(TABLE_USERTPL)->where('id')->eq($templateID)->andWhere('account')->eq($this->app->user->account)->exec(); - die(); - } - - /** - * Custom fields. - * - * @access public - * @return void - */ - public function customFields() - { - if($_POST) - { - $customFields = $this->post->customFields; - $customFields = join(',', $customFields); - setcookie('bugFields', $customFields, $this->config->cookieLife, $this->config->webRoot); - die(js::reload('parent')); - } - - $customFields = $this->cookie->bugFields ? $this->cookie->bugFields : $this->config->bug->list->defaultFields; - - $this->view->allFields = $this->bug->getFieldPairs($this->config->bug->list->allFields); - $this->view->customFields = $this->bug->getFieldPairs($customFields); - $this->view->defaultFields = $this->bug->getFieldPairs($this->config->bug->list->defaultFields); - die($this->display()); - } - - /** - * AJAX: get bugs of a user in html select. - * - * @param string $account - * @access public - * @return string - */ - public function ajaxGetUserBugs($account = '') - { - if($account == '') $account = $this->app->user->account; - $bugs = $this->bug->getUserBugPairs($account); - die(html::select('bug', $bugs, '', 'class=select-1')); - } - - /** - * AJAX: Get bug owner of a module. - * - * @param int $moduleID - * @param int $productID - * @access public - * @return string - */ - public function ajaxGetModuleOwner($moduleID, $productID = 0) - { - $owner = ''; - if($moduleID) $owner = $this->dao->findByID($moduleID)->from(TABLE_MODULE)->fetch('owner'); - if(!$owner) $owner = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('QM'); - die($owner); - } - - /** - * Send email. - * - * @param int $bugID - * @param int $actionID - * @access public - * @return void - */ - public function sendmail($bugID, $actionID) - { - /* Set toList and ccList. */ - $bug = $this->bug->getByID($bugID); - $productName = $this->products[$bug->product]; - $toList = $bug->assignedTo; - $ccList = trim($bug->mailto, ','); - if($toList == '') - { - if($ccList == '') return; - if(strpos($ccList, ',') === false) - { - $toList = $ccList; - $ccList = ''; - } - else - { - $commaPos = strpos($ccList, ','); - $toList = substr($ccList, 0, $commaPos); - $ccList = substr($ccList, $commaPos + 1); - } - } - elseif(strtolower($toList) == 'closed') - { - $toList = $bug->resolvedBy; - } - - /* Get action info. */ - $action = $this->action->getById($actionID); - $history = $this->action->getHistory($actionID); - $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); - if(strtolower($action->action) == 'opened') $action->comment = $bug->steps; - - /* Create the mail content. */ - $this->view->bug = $bug; - $this->view->action = $action; - $mailContent = $this->parse($this->moduleName, 'sendmail'); - - /* Send it. */ - $this->loadModel('mail')->send($toList, $productName . ':' . 'BUG #'. $bug->id . $this->lang->colon . $bug->title, $mailContent, $ccList); - if($this->mail->isError()) echo js::error($this->mail->getError()); - } - - /** - * Get data to export - * - * @param string $productID - * @param string $orderBy - * @access public - * @return void - */ - public function export($productID, $orderBy) - { - if($_POST) - { - $bugLang = $this->lang->bug; - $bugConfig = $this->config->bug; - - /* Create field lists. */ - $fields = explode(',', $bugConfig->list->exportFields); - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($bugLang->$fieldName) ? $bugLang->$fieldName : $fieldName; - unset($fields[$key]); - } - - /* Get bugs. */ - $bugs = $this->dao->select('*')->from(TABLE_BUG)->alias('t1')->where($this->session->bugReportCondition)->orderBy($orderBy)->fetchAll('id'); - - /* Get users, products and projects. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $products = $this->loadModel('product')->getPairs(); - $projects = $this->loadModel('project')->getPairs('all'); - - /* Get related objects id lists. */ - $relatedModuleIdList = array(); - $relatedStoryIdList = array(); - $relatedTaskIdList = array(); - $relatedBugIdList = array(); - $relatedCaseIdList = array(); - $relatedBuildIdList = array(); - - foreach($bugs as $bug) - { - $relatedModuleIdList[$bug->module] = $bug->module; - $relatedStoryIdList[$bug->story] = $bug->story; - $relatedTaskIdList[$bug->task] = $bug->task; - $relatedCaseIdList[$bug->case] = $bug->case; - $relatedBugIdList[$bug->duplicateBug] = $bug->duplicateBug; - - /* Process link bugs. */ - $linkBugs = explode(',', $bug->linkBug); - foreach($linkBugs as $linkBugID) - { - if($linkBugID) $relatedBugIdList[$linkBugID] = trim($linkBugID); - } - - /* Process builds. */ - $builds = $bug->openedBuild . ',' . $bug->resolvedBuild; - $builds = explode(',', $builds); - foreach($builds as $buildID) - { - if($buildID) $relatedBuildIdList[$buildID] = trim($buildID); - } - } - - /* Get related objects title or names. */ - $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); - $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs(); - $relatedBugs = $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($relatedBugIdList)->fetchPairs(); - $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); - $relatedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($relatedBuildIdList)->fetchPairs(); - $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('bug')->andWhere('objectID')->in(@array_keys($bugs))->fetchGroup('objectID'); - - foreach($bugs as $bug) - { - if($this->post->fileType == 'csv') - { - $bug->steps = htmlspecialchars_decode($bug->steps); - $bug->steps = str_replace("
", "\n", $bug->steps); - $bug->steps = str_replace('"', '""', $bug->steps); - $bug->steps = str_replace(' ', ' ', $bug->steps); - $bug->steps = strip_tags($bug->steps); - } - - /* fill some field with useful value. */ - if(isset($products[$bug->product])) $bug->product = $products[$bug->product]; - if(isset($projects[$bug->project])) $bug->project = $projects[$bug->project]; - if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module]; - if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story]; - if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task]; - if(isset($relatedBugs[$bug->duplicateBug])) $bug->duplicateBug = $relatedBugs[$bug->duplicateBug]; - if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case]; - - if(isset($bugLang->priList[$bug->pri])) $bug->pri = $bugLang->priList[$bug->pri]; - if(isset($bugLang->typeList[$bug->type])) $bug->type = $bugLang->typeList[$bug->type]; - if(isset($bugLang->statusList[$bug->status])) $bug->status = $bugLang->statusList[$bug->status]; - if(isset($bugLang->confirmedList[$bug->confirmed])) $bug->confirmed = $bugLang->confirmedList[$bug->confirmed]; - if(isset($bugLang->resolutionList[$bug->resolution])) $bug->resolution = $bugLang->resolutionList[$bug->resolution]; - - if(isset($users[$bug->openedBy])) $bug->openedBy = $users[$bug->openedBy]; - if(isset($users[$bug->assignedTo])) $bug->assignedTo = $users[$bug->assignedTo]; - if(isset($users[$bug->resolvedBy])) $bug->resolvedBy = $users[$bug->resolvedBy]; - if(isset($users[$bug->lastEditedBy])) $bug->lastEditedBy = $users[$bug->lastEditedBy]; - if(isset($users[$bug->closedBy])) $bug->closedBy = $users[$bug->closedBy]; - - $bug->openedDate = substr($bug->openedDate, 0, 10); - $bug->assignedDate = substr($bug->assignedDate, 0, 10); - $bug->closedDate = substr($bug->closedDate, 0, 10); - $bug->resolvedDate = substr($bug->resolvedDate, 0, 10); - $bug->lastEditedDate = substr($bug->lastEditedDate, 0, 10); - - if($bug->linkBug) - { - $tmpLinkBugs = array(); - $linkBugIdList = explode(',', $bug->linkBug); - foreach($linkBugIdList as $linkBugID) - { - $linkBugID = trim($linkBugID); - $tmpLinkBugs[] = isset($relatedBugs[$linkBugID]) ? $relatedBugs[$linkBugID] : $linkBugID; - } - $bug->linkBug = join("; \n", $tmpLinkBugs); - } - - if($bug->openedBuild) - { - $tmpOpenedBuilds = array(); - $tmpResolvedBuilds = array(); - $buildIdList = explode(',', $bug->openedBuild); - foreach($buildIdList as $buildID) - { - $buildID = trim($buildID); - $tmpOpenedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID; - } - $bug->openedBuild = join("; \n", $tmpOpenedBuilds); - } - - if($bug->resolvedBuild) - { - $buildIdList = explode(',', $bug->resolvedBuild); - foreach($buildIdList as $buildID) - { - $buildID = trim($buildID); - $tmpResolvedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID; - } - $bug->resolvedBuild = join("; \n", $tmpResolvedBuilds); - } - - /* Set related files. */ - if(isset($relatedFiles[$bug->id])) - { - foreach($relatedFiles[$bug->id] as $file) - { - $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$bug->company/" . $file->pathname; - $bug->files .= html::a($fileURL, $file->title, '_blank') . '
'; - } - } - - $bug->mailto = trim(trim($bug->mailto), ','); - $mailtos = explode(',', $bug->mailto); - $bug->mailto = ''; - foreach($mailtos as $mailto) - { - $mailto = trim($mailto); - if(isset($users[$mailto])) $bug->mailto .= $users[$mailto] . ','; - } - - /* drop some field that is not needed. */ - unset($bug->company); - unset($bug->caseVersion); - unset($bug->result); - unset($bug->deleted); - } - - $this->post->set('fields', $fields); - $this->post->set('rows', $bugs); - $this->fetch('file', 'export2' . $this->post->fileType, $_POST); - } - - $this->display(); - } -} + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +class bug extends control +{ + private $products = array(); + + /** + * Construct function, load some modules auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('product'); + $this->loadModel('tree'); + $this->loadModel('user'); + $this->loadModel('action'); + $this->loadModel('story'); + $this->loadModel('task'); + $this->products = $this->product->getPairs(); + if(empty($this->products)) + { + echo js::alert($this->lang->product->errorNoProduct); + die(js::locate($this->createLink('product', 'create'))); + } + $this->view->products = $this->products; + } + + /** + * The index page, locate to browse. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('bug', 'browse')); + } + + /** + * Browse bugs. + * + * @param int $productID + * @param string $browseType + * @param int $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Set browseType, productID, moduleID and queryID. */ + $browseType = strtolower($browseType); + $productID = $this->product->saveState($productID, $this->products); + $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Set menu and save session. */ + $this->bug->setMenu($this->products, $productID); + $this->session->set('bugList', $this->app->getURI(true)); + + /* Process the order by field. */ + if(!$orderBy) $orderBy = $this->cookie->qaBugOrder ? $this->cookie->qaBugOrder : 'id_desc'; + setcookie('qaBugOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $projects = $this->loadModel('project')->getPairs(); + $projects[0] = ''; + + /* Get bugs. */ + $bugs = array(); + if($browseType == 'all') $bugs = $this->bug->getAllBugs($productID, $projects, $orderBy, $pager); + elseif($browseType == "bymodule") + { + $childModuleIds = $this->tree->getAllChildId($moduleID); + $bugs = $this->bug->getModuleBugs($productID, $childModuleIds, $projects, $orderBy, $pager); + } + elseif($browseType == 'assigntome') $bugs = $this->bug->getByAssigntome($productID, $projects, $orderBy, $pager); + elseif($browseType == 'openedbyme') $bugs = $this->bug->getByOpenedbyme($productID, $projects, $orderBy, $pager); + elseif($browseType == 'resolvedbyme') $bugs = $this->bug->getByResolvedbyme($productID, $projects, $orderBy, $pager); + elseif($browseType == 'assigntonull') $bugs = $this->bug->getByAssigntonull($productID, $projects, $orderBy, $pager); + elseif($browseType == 'unresolved') $bugs = $this->bug->getByStatus($productID, $projects, 'unresolved', $orderBy, $pager); + elseif($browseType == 'unclosed') $bugs = $this->bug->getByStatus($productID, $projects, 'unclosed', $orderBy, $pager); + elseif($browseType == 'longlifebugs') $bugs = $this->bug->getByLonglifebugs($productID, $projects, $orderBy, $pager); + elseif($browseType == 'postponedbugs') $bugs = $this->bug->getByPostponedbugs($productID, $projects, $orderBy, $pager); + elseif($browseType == 'needconfirm') $bugs = $this->bug->getByNeedconfirm($productID, $projects, $orderBy, $pager); + elseif($browseType == 'bysearch') $bugs = $this->bug->getBySearch($productID, $projects, $queryID, $orderBy, $pager); + + /* Process the sql, get the conditon partion, save it to session. Thus the report page can use the same condition. */ + if($browseType != 'needconfirm') + { + $sql = explode('WHERE', $this->dao->get()); + $sql = explode('ORDER', $sql[1]); + $this->session->set('bugReportCondition', $sql[0]); + } + + /* Get custom fields. */ + $customFields = $this->cookie->bugFields != false ? $this->cookie->bugFields : $this->config->bug->list->defaultFields; + $customed = !($customFields == $this->config->bug->list->defaultFields); + + /* If customed, get related name or titles. */ + if($customed) $bugs = $this->bug->formCustomedBugs($bugs); + + /* Build the search form. */ + $this->config->bug->search['actionURL'] = $this->createLink('bug', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); + $this->config->bug->search['queryID'] = $queryID; + $this->config->bug->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->bug->allProduct); + $this->config->bug->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); + $this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID); + $this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID); + $this->config->bug->search['params']['resolvedBuild']['values'] = $this->build->getProductBuildPairs($productID); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search); + + $users = $this->user->getPairs('noletter'); + + $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common; + $position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $position[] = $this->lang->bug->common; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'bug', $startModuleID = 0, array('treeModel', 'createBugLink')); + $this->view->browseType = $browseType; + $this->view->bugs = $bugs; + $this->view->users = $users; + $this->view->pager = $pager; + $this->view->param = $param; + $this->view->orderBy = $orderBy; + $this->view->moduleID = $moduleID; + $this->view->customed = $customed; + $this->view->customFields= explode(',', str_replace(' ', '', trim($customFields))); + $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; + + $this->display(); + } + + /** + * The report page. + * + * @param int $productID + * @param string $browseType + * @param int $moduleID + * @access public + * @return void + */ + public function report($productID, $browseType, $moduleID) + { + $this->loadModel('report'); + $this->view->charts = array(); + $this->view->renderJS = ''; + + if(!empty($_POST)) + { + foreach($this->post->charts as $chart) + { + $chartFunc = 'getDataOf' . $chart; + $chartData = $this->bug->$chartFunc(); + $chartOption = $this->lang->bug->report->$chart; + $this->bug->mergeChartOption($chart); + + $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); + $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); + $this->view->datas[$chart] = $this->report->computePercent($chartData); + } + $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); + } + + $this->bug->setMenu($this->products, $productID); + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->common; + $this->view->productID = $productID; + $this->view->browseType = $browseType; + $this->view->moduleID = $moduleID; + $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; + $this->display(); + } + + /** + * Create a bug. + * + * @param int $productID + * @param string $extras others params, forexample, projectID=10,moduleID=10 + * @access public + * @return void + */ + public function create($productID, $extras = '') + { + $this->view->users = $this->user->getPairs('nodeleted'); + if(empty($this->products)) $this->locate($this->createLink('product', 'create')); + + if(!empty($_POST)) + { + $bugID = $this->bug->create(); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Opened'); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'browse', "productID={$this->post->product}&type=byModule¶m={$this->post->module}"), 'parent')); + } + + /* Get product, then set menu. */ + $productID = $this->product->saveState($productID, $this->products); + $this->bug->setMenu($this->products, $productID); + + /* Remove the unused types. */ + unset($this->lang->bug->typeList['designchange']); + unset($this->lang->bug->typeList['newfeature']); + unset($this->lang->bug->typeList['trackthings']); + + /* Init vars. */ + $moduleID = 0; + $projectID = 0; + $taskID = 0; + $storyID = 0; + $buildID = 0; + $caseID = 0; + $runID = 0; + $title = ''; + $steps = $this->lang->bug->tplStep . $this->lang->bug->tplResult . $this->lang->bug->tplExpect; + $os = ''; + $browser = ''; + $assignedTo = ''; + $mailto = ''; + $keywords = ''; + $severity = 3; + $type = 'codeerror'; + + /* Parse the extras. */ + $extras = str_replace(array(',', ' '), array('&', ''), $extras); + parse_str($extras); + + /* If set runID, get the last result info as the template. */ + if($runID > 0) $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->limit(1)->fetch('id'); + if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID)); + + /* If set caseID and runID='', get the last result info as the template. */ + if($caseID > 0 && $runID == '') + { + $resultID = $this->dao->select('id')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('date desc')->limit(1)->fetch('id'); + if(isset($resultID) and $resultID > 0) extract($this->bug->getBugInfoFromResult($resultID, $caseID, $version)); + } + + /* If bugID setted, use this bug as template. */ + if(isset($bugID)) + { + $bug = $this->bug->getById($bugID); + extract((array)$bug); + $projectID = $bug->project; + $moduleID = $bug->module; + $taskID = $bug->task; + $storyID = $bug->story; + $buildID = $bug->openedBuild; + $severity = $bug->severity; + $type = $bug->type; + } + + /* If projectID is setted, get builds and stories of this project. */ + if($projectID) + { + $builds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty'); + $stories = $this->story->getProjectStoryPairs($projectID); + } + else + { + $builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); + $stories = $this->story->getProductStoryPairs($productID); + } + + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->create; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->create; + + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); + $this->view->stories = $stories; + $this->view->projects = $this->product->getProjectPairs($productID, $params = 'nodeleted'); + $this->view->builds = $builds; + $this->view->tasks = $this->loadModel('task')->getProjectTaskPairs($projectID); + $this->view->moduleID = $moduleID; + $this->view->projectID = $projectID; + $this->view->taskID = $taskID; + $this->view->storyID = $storyID; + $this->view->buildID = $buildID; + $this->view->caseID = $caseID; + $this->view->title = $title; + $this->view->steps = htmlspecialchars($steps); + $this->view->os = $os; + $this->view->browser = $browser; + $this->view->assignedTo = $assignedTo; + $this->view->mailto = $mailto; + $this->view->keywords = $keywords; + $this->view->severity = $severity; + $this->view->type = $type; + + $this->display(); + } + + /** + * View a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function view($bugID) + { + /* Judge bug exits or not. */ + $bug = $this->bug->getById($bugID); + if(!$bug) die(js::error($this->lang->notFound) . js::locate('back')); + + /* Set menu. */ + $this->bug->setMenu($this->products, $bug->product); + + /* Get product info. */ + $productID = $bug->product; + $productName = $this->products[$productID]; + + /* Header and positon. */ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->view; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $productName); + $this->view->position[] = $this->lang->bug->view; + + /* Assign. */ + $this->view->productID = $productID; + $this->view->productName = $productName; + $this->view->modulePath = $this->tree->getParents($bug->module); + $this->view->bug = $bug; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + + $this->display(); + } + + /** + * Edit a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function edit($bugID, $comment = false) + { + if(!empty($_POST)) + { + $changes = array(); + $files = array(); + if($comment == false) + { + $changes = $this->bug->update($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('bug', $bugID); + } + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $action = !empty($changes) ? 'Edited' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; + $actionID = $this->action->create('bug', $bugID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($bugID, $actionID); + } + + $bug = $this->bug->getById($bugID); + if($bug->toTask != 0) + { + foreach($changes as $change) + { + if($change['field'] == 'status') + { + $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); + $cancelURL = $this->server->HTTP_REFERER; + die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->Task), $confirmURL, $cancelURL, 'parent', 'parent')); + } + } + } + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + /* Get the info of bug, current product and modue. */ + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $projectID = $bug->project; + $currentModuleID = $bug->module; + + /** + * Remove designchange, newfeature, trackings from the typeList, because should be tracked in story or task. + * These thress types if upgrade from bugfree2.x. + */ + if($bug->type != 'designchange') unset($this->lang->bug->typeList['designchange']); + if($bug->type != 'newfeature') unset($this->lang->bug->typeList['newfeature']); + if($bug->type != 'trackthings') unset($this->lang->bug->typeList['trackthings']); + + /* Set the menu. */ + $this->bug->setMenu($this->products, $productID); + + /* Set header and position. */ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->edit; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->edit; + + /* Assign. */ + if($projectID) + { + $this->view->openedBuilds = $this->loadModel('build')->getProjectBuildPairs($projectID, $productID, 'noempty'); + } + else + { + $this->view->openedBuilds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); + } + $this->view->bug = $bug; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0); + $this->view->currentModuleID = $currentModuleID; + $this->view->projects = $this->product->getProjectPairs($bug->product); + $this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product); + $this->view->tasks = $this->task->getProjectTaskPairs($bug->project); + $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy"); + $this->view->resolvedBuilds = array('' => '') + $this->view->openedBuilds; + $this->view->actions = $this->action->getList('bug', $bugID); + $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account); + + $this->display(); + } + + /** + * confirm a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function confirmBug($bugID) + { + if(!empty($_POST)) + { + $this->bug->confirm($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'bugConfirmed', $this->post->comment); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $this->bug->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->confirmBug; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->confirmBug; + + $this->view->bug = $bug; + $this->view->actions = $this->action->getList('bug', $bugID); + $this->display(); + } + + /** + * Resolve a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function resolve($bugID) + { + $this->view->users = $this->user->getPairs('nodeleted'); + + if(!empty($_POST)) + { + $this->bug->resolve($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Resolved', $this->post->comment, $this->post->resolution); + $this->sendmail($bugID, $actionID); + + $bug = $this->bug->getById($bugID); + if($bug->toTask != 0) + { + $confirmURL = $this->createLink('task', 'view', "taskID=$bug->toTask"); + $cancelURL = $this->createLink('bug', 'view', "bugID=$bugID"); + die(js::confirm(sprintf($this->lang->bug->remindTask, $bug->toTask), $confirmURL, $cancelURL, 'parent', 'parent')); + } + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $this->bug->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->bug->resolve; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->resolve; + + $this->view->bug = $bug; + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->actions = $this->action->getList('bug', $bugID); + $this->display(); + } + + /** + * Activate a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function activate($bugID) + { + $this->view->users = $this->user->getPairs('nodeleted'); + + if(!empty($_POST)) + { + $this->bug->activate($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('bug', $bugID); + $actionID = $this->action->create('bug', $bugID, 'Activated', $this->post->comment); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $this->bug->setMenu($this->products, $productID); + + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->activate; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->activate; + + $this->view->bug = $bug; + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID, 'noempty'); + $this->view->actions = $this->action->getList('bug', $bugID); + + $this->display(); + } + + /** + * Close a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function close($bugID) + { + $this->view->users = $this->user->getPairs('noletter'); + if(!empty($_POST)) + { + $this->bug->close($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('bug', $bugID, 'Closed', $this->post->comment); + $this->sendmail($bugID, $actionID); + die(js::locate($this->createLink('bug', 'view', "bugID=$bugID"), 'parent')); + } + + $bug = $this->bug->getById($bugID); + $productID = $bug->product; + $this->bug->setMenu($this->products, $productID); + + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->bug->close; + $this->view->position[] = html::a($this->createLink('bug', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->bug->close; + + $this->view->bug = $bug; + $this->view->actions = $this->action->getList('bug', $bugID); + $this->display(); + } + + /** + * Confirm story change. + * + * @param int $bugID + * @access public + * @return void + */ + public function confirmStoryChange($bugID) + { + $bug = $this->bug->getById($bugID); + $this->dao->update(TABLE_BUG)->set('storyVersion')->eq($bug->latestStoryVersion)->where('id')->eq($bugID)->exec(); + $this->loadModel('action')->create('bug', $bugID, 'confirmed', '', $bug->latestStoryVersion); + die(js::reload('parent')); + } + + /** + * Delete a bug. + * + * @param int $bugID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($bugID, $confirm = 'no') + { + $bug = $this->bug->getById($bugID); + if($confirm == 'no') + { + die(js::confirm($this->lang->bug->confirmDelete, inlink('delete', "bugID=$bugID&confirm=yes"))); + } + else + { + $this->bug->delete(TABLE_BUG, $bugID); + if($bug->toTask != 0) echo js::alert($this->lang->bug->remindTask . $bug->toTask); + die(js::locate($this->session->bugList, 'parent')); + } + } + + /** + * Save current template. + * + * @access public + * @return string + */ + public function saveTemplate() + { + $this->bug->saveUserBugTemplate(); + if(dao::isError()) die(js::error(dao::getError())); + die($this->fetch('bug', 'buildTemplates')); + } + + /** + * Build the user templates selection code. + * + * @access public + * @return void + */ + public function buildTemplates() + { + $this->view->templates = $this->bug->getUserBugTemplates($this->app->user->account); + $this->display('bug', 'buildTemplates'); + } + + /** + * Delete a user template. + * + * @param int $templateID + * @access public + * @return void + */ + public function deleteTemplate($templateID) + { + $this->dao->delete()->from(TABLE_USERTPL)->where('id')->eq($templateID)->andWhere('account')->eq($this->app->user->account)->exec(); + die(); + } + + /** + * Custom fields. + * + * @access public + * @return void + */ + public function customFields() + { + if($_POST) + { + $customFields = $this->post->customFields; + $customFields = join(',', $customFields); + setcookie('bugFields', $customFields, $this->config->cookieLife, $this->config->webRoot); + die(js::reload('parent')); + } + + $customFields = $this->cookie->bugFields ? $this->cookie->bugFields : $this->config->bug->list->defaultFields; + + $this->view->allFields = $this->bug->getFieldPairs($this->config->bug->list->allFields); + $this->view->customFields = $this->bug->getFieldPairs($customFields); + $this->view->defaultFields = $this->bug->getFieldPairs($this->config->bug->list->defaultFields); + die($this->display()); + } + + /** + * AJAX: get bugs of a user in html select. + * + * @param string $account + * @access public + * @return string + */ + public function ajaxGetUserBugs($account = '') + { + if($account == '') $account = $this->app->user->account; + $bugs = $this->bug->getUserBugPairs($account); + die(html::select('bug', $bugs, '', 'class=select-1')); + } + + /** + * AJAX: Get bug owner of a module. + * + * @param int $moduleID + * @param int $productID + * @access public + * @return string + */ + public function ajaxGetModuleOwner($moduleID, $productID = 0) + { + $owner = ''; + if($moduleID) $owner = $this->dao->findByID($moduleID)->from(TABLE_MODULE)->fetch('owner'); + if(!$owner) $owner = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('QM'); + die($owner); + } + + /** + * Send email. + * + * @param int $bugID + * @param int $actionID + * @access public + * @return void + */ + public function sendmail($bugID, $actionID) + { + /* Set toList and ccList. */ + $bug = $this->bug->getByID($bugID); + $productName = $this->products[$bug->product]; + $toList = $bug->assignedTo; + $ccList = trim($bug->mailto, ','); + if($toList == '') + { + if($ccList == '') return; + if(strpos($ccList, ',') === false) + { + $toList = $ccList; + $ccList = ''; + } + else + { + $commaPos = strpos($ccList, ','); + $toList = substr($ccList, 0, $commaPos); + $ccList = substr($ccList, $commaPos + 1); + } + } + elseif(strtolower($toList) == 'closed') + { + $toList = $bug->resolvedBy; + } + + /* Get action info. */ + $action = $this->action->getById($actionID); + $history = $this->action->getHistory($actionID); + $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); + if(strtolower($action->action) == 'opened') $action->comment = $bug->steps; + + /* Create the mail content. */ + $this->view->bug = $bug; + $this->view->action = $action; + $mailContent = $this->parse($this->moduleName, 'sendmail'); + + /* Send it. */ + $this->loadModel('mail')->send($toList, $productName . ':' . 'BUG #'. $bug->id . $this->lang->colon . $bug->title, $mailContent, $ccList); + if($this->mail->isError()) echo js::error($this->mail->getError()); + } + + /** + * Get data to export + * + * @param string $productID + * @param string $orderBy + * @access public + * @return void + */ + public function export($productID, $orderBy) + { + if($_POST) + { + $bugLang = $this->lang->bug; + $bugConfig = $this->config->bug; + + /* Create field lists. */ + $fields = explode(',', $bugConfig->list->exportFields); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($bugLang->$fieldName) ? $bugLang->$fieldName : $fieldName; + unset($fields[$key]); + } + + /* Get bugs. */ + $bugs = $this->dao->select('*')->from(TABLE_BUG)->alias('t1')->where($this->session->bugReportCondition)->orderBy($orderBy)->fetchAll('id'); + + /* Get users, products and projects. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $products = $this->loadModel('product')->getPairs(); + $projects = $this->loadModel('project')->getPairs('all'); + + /* Get related objects id lists. */ + $relatedModuleIdList = array(); + $relatedStoryIdList = array(); + $relatedTaskIdList = array(); + $relatedBugIdList = array(); + $relatedCaseIdList = array(); + $relatedBuildIdList = array(); + + foreach($bugs as $bug) + { + $relatedModuleIdList[$bug->module] = $bug->module; + $relatedStoryIdList[$bug->story] = $bug->story; + $relatedTaskIdList[$bug->task] = $bug->task; + $relatedCaseIdList[$bug->case] = $bug->case; + $relatedBugIdList[$bug->duplicateBug] = $bug->duplicateBug; + + /* Process link bugs. */ + $linkBugs = explode(',', $bug->linkBug); + foreach($linkBugs as $linkBugID) + { + if($linkBugID) $relatedBugIdList[$linkBugID] = trim($linkBugID); + } + + /* Process builds. */ + $builds = $bug->openedBuild . ',' . $bug->resolvedBuild; + $builds = explode(',', $builds); + foreach($builds as $buildID) + { + if($buildID) $relatedBuildIdList[$buildID] = trim($buildID); + } + } + + /* Get related objects title or names. */ + $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); + $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs(); + $relatedBugs = $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($relatedBugIdList)->fetchPairs(); + $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); + $relatedBuilds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->in($relatedBuildIdList)->fetchPairs(); + $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('bug')->andWhere('objectID')->in(@array_keys($bugs))->fetchGroup('objectID'); + + foreach($bugs as $bug) + { + if($this->post->fileType == 'csv') + { + $bug->steps = htmlspecialchars_decode($bug->steps); + $bug->steps = str_replace("
", "\n", $bug->steps); + $bug->steps = str_replace('"', '""', $bug->steps); + $bug->steps = str_replace(' ', ' ', $bug->steps); + $bug->steps = strip_tags($bug->steps); + } + + /* fill some field with useful value. */ + if(isset($products[$bug->product])) $bug->product = $products[$bug->product]; + if(isset($projects[$bug->project])) $bug->project = $projects[$bug->project]; + if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module]; + if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story]; + if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task]; + if(isset($relatedBugs[$bug->duplicateBug])) $bug->duplicateBug = $relatedBugs[$bug->duplicateBug]; + if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case]; + + if(isset($bugLang->priList[$bug->pri])) $bug->pri = $bugLang->priList[$bug->pri]; + if(isset($bugLang->typeList[$bug->type])) $bug->type = $bugLang->typeList[$bug->type]; + if(isset($bugLang->statusList[$bug->status])) $bug->status = $bugLang->statusList[$bug->status]; + if(isset($bugLang->confirmedList[$bug->confirmed])) $bug->confirmed = $bugLang->confirmedList[$bug->confirmed]; + if(isset($bugLang->resolutionList[$bug->resolution])) $bug->resolution = $bugLang->resolutionList[$bug->resolution]; + + if(isset($users[$bug->openedBy])) $bug->openedBy = $users[$bug->openedBy]; + if(isset($users[$bug->assignedTo])) $bug->assignedTo = $users[$bug->assignedTo]; + if(isset($users[$bug->resolvedBy])) $bug->resolvedBy = $users[$bug->resolvedBy]; + if(isset($users[$bug->lastEditedBy])) $bug->lastEditedBy = $users[$bug->lastEditedBy]; + if(isset($users[$bug->closedBy])) $bug->closedBy = $users[$bug->closedBy]; + + $bug->openedDate = substr($bug->openedDate, 0, 10); + $bug->assignedDate = substr($bug->assignedDate, 0, 10); + $bug->closedDate = substr($bug->closedDate, 0, 10); + $bug->resolvedDate = substr($bug->resolvedDate, 0, 10); + $bug->lastEditedDate = substr($bug->lastEditedDate, 0, 10); + + if($bug->linkBug) + { + $tmpLinkBugs = array(); + $linkBugIdList = explode(',', $bug->linkBug); + foreach($linkBugIdList as $linkBugID) + { + $linkBugID = trim($linkBugID); + $tmpLinkBugs[] = isset($relatedBugs[$linkBugID]) ? $relatedBugs[$linkBugID] : $linkBugID; + } + $bug->linkBug = join("; \n", $tmpLinkBugs); + } + + if($bug->openedBuild) + { + $tmpOpenedBuilds = array(); + $tmpResolvedBuilds = array(); + $buildIdList = explode(',', $bug->openedBuild); + foreach($buildIdList as $buildID) + { + $buildID = trim($buildID); + $tmpOpenedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID; + } + $bug->openedBuild = join("; \n", $tmpOpenedBuilds); + } + + if($bug->resolvedBuild) + { + $buildIdList = explode(',', $bug->resolvedBuild); + foreach($buildIdList as $buildID) + { + $buildID = trim($buildID); + $tmpResolvedBuilds[] = isset($relatedBuilds[$buildID]) ? $relatedBuilds[$buildID] : $buildID; + } + $bug->resolvedBuild = join("; \n", $tmpResolvedBuilds); + } + + /* Set related files. */ + if(isset($relatedFiles[$bug->id])) + { + foreach($relatedFiles[$bug->id] as $file) + { + $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$bug->company/" . $file->pathname; + $bug->files .= html::a($fileURL, $file->title, '_blank') . '
'; + } + } + + $bug->mailto = trim(trim($bug->mailto), ','); + $mailtos = explode(',', $bug->mailto); + $bug->mailto = ''; + foreach($mailtos as $mailto) + { + $mailto = trim($mailto); + if(isset($users[$mailto])) $bug->mailto .= $users[$mailto] . ','; + } + + /* drop some field that is not needed. */ + unset($bug->company); + unset($bug->caseVersion); + unset($bug->result); + unset($bug->deleted); + } + + $this->post->set('fields', $fields); + $this->post->set('rows', $bugs); + $this->fetch('file', 'export2' . $this->post->fileType, $_POST); + } + + $this->display(); + } +} diff --git a/module/bug/lang/en.php b/module/bug/lang/en.php index 23e577b833..e2cc7be4eb 100644 --- a/module/bug/lang/en.php +++ b/module/bug/lang/en.php @@ -1,312 +1,312 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -/* Fieldlist. */ -$lang->bug->common = 'Bug'; -$lang->bug->id = 'ID'; -$lang->bug->product = 'Product'; -$lang->bug->module = 'Module'; -$lang->bug->path = 'Path'; -$lang->bug->project = 'Project'; -$lang->bug->story = 'Story'; -$lang->bug->storyVersion = 'Story Version'; -$lang->bug->task = 'Task'; -$lang->bug->title = 'Title'; -$lang->bug->severity = 'Severity'; -$lang->bug->severityAB = 'S'; -$lang->bug->pri = 'Priority'; -$lang->bug->type = 'Type'; -$lang->bug->os = 'OS'; -$lang->bug->hardware = 'Hardware'; -$lang->bug->browser = 'Browser'; -$lang->bug->machine = 'Machine'; -$lang->bug->found = 'How found'; -$lang->bug->steps = 'Steps'; -$lang->bug->status = 'Status'; -$lang->bug->statusAB = 'Status'; -$lang->bug->activatedCount = 'Activated count'; -$lang->bug->activatedCountAB = 'Activated count'; -$lang->bug->confirmed = 'Confirmed'; -$lang->bug->toTask = 'To task'; -$lang->bug->toStory = 'To story'; -$lang->bug->mailto = 'Mailto'; -$lang->bug->openedBy = 'Opened By'; -$lang->bug->openedByAB = 'Opened'; -$lang->bug->openedDate = 'Opened date'; -$lang->bug->openedDateAB = 'Date'; -$lang->bug->openedBuild = 'Opened Build'; -$lang->bug->assignedTo = 'Assigned'; -$lang->bug->assignedDate = 'Assigned Date'; -$lang->bug->resolvedBy = 'Resolved By'; -$lang->bug->resolvedByAB = 'Resolve'; -$lang->bug->resolution = 'Resolution'; -$lang->bug->resolutionAB = 'Resolution'; -$lang->bug->resolvedBuild = 'Resolved Build'; -$lang->bug->resolvedDate = 'Resolved Date'; -$lang->bug->resolvedDateAB = 'Date'; -$lang->bug->closedBy = 'Closed By'; -$lang->bug->closedDate = 'Closed Date'; -$lang->bug->duplicateBug = 'Duplicate'; -$lang->bug->lastEditedBy = 'Last Edited By'; -$lang->bug->lastEditedDate = 'Last Edited Date'; -$lang->bug->linkBug = 'Related'; -$lang->bug->case = 'Case'; -$lang->bug->files = 'Files'; -$lang->bug->keywords = 'Keywords'; -$lang->bug->lastEditedByAB = 'Edited'; -$lang->bug->lastEditedDateAB = 'Edited Date'; - -/* Actions. */ -$lang->bug->index = 'Index'; -$lang->bug->create = 'Create Bug'; -$lang->bug->confirmBug = 'Confirm Bug'; -$lang->bug->edit = 'Edit Bug'; -$lang->bug->browse = 'Browse Bug'; -$lang->bug->view = 'Bug Info'; -$lang->bug->resolve = 'Resolve Bug'; -$lang->bug->close = 'Close Bug'; -$lang->bug->activate = 'Activate Bug'; -$lang->bug->reportChart = 'Report'; -$lang->bug->export = 'Export data'; -$lang->bug->delete = 'Delete Bug'; -$lang->bug->saveTemplate = 'Save template'; -$lang->bug->deleteTemplate = 'Delete template'; -$lang->bug->customFields = 'Custom'; -$lang->bug->restoreDefault = 'Default'; -$lang->bug->ajaxGetUserBugs = 'API: My Bugs'; -$lang->bug->ajaxGetModuleOwner = 'API: Get module default owner'; -$lang->bug->confirmStoryChange = 'Confirm Story Change'; - -/* Browse tabs. */ -$lang->bug->selectProduct = 'Select product'; -$lang->bug->byModule = 'ByModule'; -$lang->bug->assignToMe = 'MyBugs'; -$lang->bug->openedByMe = 'MyOpen'; -$lang->bug->resolvedByMe = 'MyResolve'; -$lang->bug->closedByMe = 'MyClose'; -$lang->bug->assignToNull = 'Unassigned'; -$lang->bug->unResolved = 'Unresolved'; -$lang->bug->unclosed = 'Unclosed'; -$lang->bug->longLifeBugs = 'Longlife'; -$lang->bug->postponedBugs = 'Postponed'; -$lang->bug->allBugs = 'Allbug'; -$lang->bug->moduleBugs = 'ByModule'; -$lang->bug->byQuery = 'Search'; -$lang->bug->needConfirm = 'StoryChanged'; -$lang->bug->allProduct = 'All products'; - -/* Labels. */ -$lang->bug->lblProductAndModule = 'Product&Module'; -$lang->bug->lblProjectAndTask = 'Project&Task'; -$lang->bug->lblStory = 'Story'; -$lang->bug->lblTypeAndSeverity = 'Type&Severity'; -$lang->bug->lblSystemBrowserAndHardware = 'OS&Browser'; -$lang->bug->lblAssignedTo = 'Assigned to'; -$lang->bug->lblMailto = 'Mailto'; -$lang->bug->lblLastEdited = 'Last edited'; -$lang->bug->lblResolved = 'Resolved'; -$lang->bug->lblAllFields = 'All Fields'; -$lang->bug->lblCustomFields = 'Custom Fields'; - -/* Legends. */ -$lang->bug->legendBasicInfo = 'Basic info'; -$lang->bug->legendMailto = 'Mailto'; -$lang->bug->legendAttatch = 'Files'; -$lang->bug->legendLinkBugs = 'Related bug'; -$lang->bug->legendPrjStoryTask = 'Project, story & task'; -$lang->bug->legendCases = 'Related case'; -$lang->bug->legendSteps = 'Steps'; -$lang->bug->legendAction = 'Action'; -$lang->bug->legendHistory = 'History'; -$lang->bug->legendComment = 'Comment'; -$lang->bug->legendLife = 'Lifetime'; -$lang->bug->legendMisc = 'Misc'; - -/* Action buttons. */ -$lang->bug->buttonConfirm = 'Confirm'; -$lang->bug->buttonCopy = 'Copy'; -$lang->bug->buttonEdit = 'Edit'; -$lang->bug->buttonActivate = 'Activate'; -$lang->bug->buttonResolve = 'Resolve'; -$lang->bug->buttonClose = 'Close'; -$lang->bug->buttonToList = 'Back'; -$lang->bug->buttonCreateTestcase = 'Create case'; - -/* Confirm messags. */ -$lang->bug->confirmChangeProduct = 'Change product will change project, task and story also, are you sure?'; -$lang->bug->confirmDelete = 'Are you sure to delete this bug?'; -$lang->bug->setTemplateTitle = 'Please input the template title:'; -$lang->bug->remindTask = 'This bug has been to be a task, update the task:%s or not?'; - -/* Templates. */ -$lang->bug->tplStep = "

[Steps]

"; -$lang->bug->tplResult = "

[Result]

"; -$lang->bug->tplExpect = "

[Expect]

"; - -/* Field options lists. */ -$lang->bug->severityList[3] = '3'; -$lang->bug->severityList[1] = '1'; -$lang->bug->severityList[2] = '2'; -$lang->bug->severityList[4] = '4'; - -$lang->bug->priList[0] = ''; -$lang->bug->priList[3] = '3'; -$lang->bug->priList[1] = '1'; -$lang->bug->priList[2] = '2'; -$lang->bug->priList[4] = '4'; - -$lang->bug->osList[''] = ''; -$lang->bug->osList['all'] = 'All'; -$lang->bug->osList['windows'] = 'Windows'; -$lang->bug->osList['winxp'] = 'Windows XP'; -$lang->bug->osList['win7'] = 'Windows 7'; -$lang->bug->osList['vista'] = 'Windows Vista'; -$lang->bug->osList['win2000'] = 'Windows 2000'; -$lang->bug->osList['win2003'] = 'Windows 2003'; -$lang->bug->osList['win2008'] = 'Windows 2008'; -$lang->bug->osList['winnt'] = 'Windows NT'; -$lang->bug->osList['win98'] = 'Windows 98'; -$lang->bug->osList['andriod'] = 'Andriod'; -$lang->bug->osList['ios'] = 'IOS'; -$lang->bug->osList['wp7'] = 'WP7'; -$lang->bug->osList['symbian'] = 'Symbian'; -$lang->bug->osList['linux'] = 'Linux'; -$lang->bug->osList['freebsd'] = 'FreeBSD'; -$lang->bug->osList['mac'] = 'Mac OS'; -$lang->bug->osList['unix'] = 'Unix'; -$lang->bug->osList['others'] = 'Others'; - -$lang->bug->browserList[''] = ''; -$lang->bug->browserList['all'] = 'All'; -$lang->bug->browserList['ie'] = 'IE'; -$lang->bug->browserList['ie8'] = 'IE8'; -$lang->bug->browserList['ie9'] = 'IE9'; -$lang->bug->browserList['ie6'] = 'IE6'; -$lang->bug->browserList['ie7'] = 'IE7'; -$lang->bug->browserList['chrome'] = 'chrome'; -$lang->bug->browserList['firefox'] = 'Firefox'; -$lang->bug->browserList['firefox2'] = 'Firefox2'; -$lang->bug->browserList['firefox3'] = 'Firefox3'; -$lang->bug->browserList['firefox4'] = 'Firefox4'; -$lang->bug->browserList['opera'] = 'opera'; -$lang->bug->browserList['opera9'] = 'opera9'; -$lang->bug->browserList['oprea10'] = 'opera10'; -$lang->bug->browserList['oprea11'] = 'opera11'; -$lang->bug->browserList['safari'] = 'safari'; -$lang->bug->browserList['maxthon'] = '傲游'; -$lang->bug->browserList['uc'] = 'UC'; -$lang->bug->browserList['other'] = 'Others'; - -$lang->bug->typeList[''] = ''; -$lang->bug->typeList['codeerror'] = 'Code error'; -$lang->bug->typeList['interface'] = 'Interface'; -$lang->bug->typeList['designchange'] = 'Design change'; -$lang->bug->typeList['newfeature'] = 'New feature'; -$lang->bug->typeList['designdefect'] = 'Design defect'; -$lang->bug->typeList['config'] = 'Config'; -$lang->bug->typeList['install'] = 'Install'; -$lang->bug->typeList['security'] = 'Security'; -$lang->bug->typeList['performance'] = 'Performance'; -$lang->bug->typeList['standard'] = 'Standard'; -$lang->bug->typeList['automation'] = 'Automation'; -$lang->bug->typeList['trackthings'] = 'Tracking'; -$lang->bug->typeList['others'] = 'Others'; - -$lang->bug->statusList[''] = ''; -$lang->bug->statusList['active'] = 'Active'; -$lang->bug->statusList['resolved'] = 'Resolved'; -$lang->bug->statusList['closed'] = 'Closed'; - -$lang->bug->confirmedList[1] = 'Confirmed'; -$lang->bug->confirmedList[0] = 'Unconfirmed'; - -$lang->bug->resolutionList[''] = ''; -$lang->bug->resolutionList['bydesign'] = 'By design'; -$lang->bug->resolutionList['duplicate'] = 'Duplicate'; -$lang->bug->resolutionList['external'] = 'External'; -$lang->bug->resolutionList['fixed'] = 'Fixed'; -$lang->bug->resolutionList['notrepro'] = 'Not reproduce'; -$lang->bug->resolutionList['postponed'] = 'Postponed'; -$lang->bug->resolutionList['willnotfix'] = "Won't fix"; -$lang->bug->resolutionList['tostory'] = 'To story'; - -/* Report. */ -$lang->bug->report->common = 'Report'; -$lang->bug->report->select = 'Select'; -$lang->bug->report->create = 'Create'; -$lang->bug->report->selectAll = 'All'; -$lang->bug->report->selectReverse = 'Reverse'; - -$lang->bug->report->charts['bugsPerProject'] = 'Project bugs'; -$lang->bug->report->charts['bugsPerModule'] = 'Module bugs'; -$lang->bug->report->charts['openedBugsPerDay'] = 'Opened bugs per day'; -$lang->bug->report->charts['resolvedBugsPerDay'] = 'Resolved bugs per day'; -$lang->bug->report->charts['closedBugsPerDay'] = 'Closed bugs per day'; -$lang->bug->report->charts['openedBugsPerUser'] = 'Opened bugs per user'; -$lang->bug->report->charts['resolvedBugsPerUser'] = 'Resolved bugs per user'; -$lang->bug->report->charts['closedBugsPerUser'] = 'Closed bugs per user'; -$lang->bug->report->charts['bugsPerSeverity'] = 'Severity'; -$lang->bug->report->charts['bugsPerResolution'] = 'Resolution'; -$lang->bug->report->charts['bugsPerStatus'] = 'Status'; -$lang->bug->report->charts['bugsPerActivatedCount'] = 'Activated count'; -$lang->bug->report->charts['bugsPerType'] = 'Type'; -$lang->bug->report->charts['bugsPerAssignedTo'] = 'AssignedTo'; -//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计'; -//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计'; - -$lang->bug->report->options->swf = 'pie2d'; -$lang->bug->report->options->width = 'auto'; -$lang->bug->report->options->height = 300; -$lang->bug->report->options->graph->baseFontSize = 12; -$lang->bug->report->options->graph->showNames = 1; -$lang->bug->report->options->graph->formatNumber = 1; -$lang->bug->report->options->graph->decimalPrecision = 0; -$lang->bug->report->options->graph->animation = 0; -$lang->bug->report->options->graph->rotateNames = 0; -$lang->bug->report->options->graph->yAxisName = 'COUNT'; -$lang->bug->report->options->graph->pieRadius = 100; -$lang->bug->report->options->graph->showColumnShadow = 0; - -$lang->bug->report->bugsPerProject->graph->xAxisName = 'Project'; -$lang->bug->report->bugsPerModule->graph->xAxisName = 'Module'; - -$lang->bug->report->openedBugsPerDay->swf = 'column2d'; -$lang->bug->report->openedBugsPerDay->height = 400; -$lang->bug->report->openedBugsPerDay->graph->xAxisName = 'Date'; -$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; -$lang->bug->report->resolvedBugsPerDay->height = 400; -$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = 'Date'; -$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->closedBugsPerDay->swf = 'column2d'; -$lang->bug->report->closedBugsPerDay->height = 400; -$lang->bug->report->closedBugsPerDay->graph->xAxisName = 'Date'; -$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->openedBugsPerUser->graph->xAxisName = 'User'; -$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= 'User'; -$lang->bug->report->closedBugsPerUser->graph->xAxisName = 'User'; - -$lang->bug->report->bugsPerSeverity->graph->xAxisName = 'Severity'; -$lang->bug->report->bugsPerResolution->graph->xAxisName = 'Resolution'; -$lang->bug->report->bugsPerStatus->graph->xAxisName = 'Status'; -$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = 'Activated count'; -$lang->bug->report->bugsPerType->graph->xAxisName = 'Type'; -$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = 'AssignedTo'; -$lang->bug->report->bugLiveDays->graph->xAxisName = 'Live days'; -$lang->bug->report->bugHistories->graph->xAxisName = 'Histories'; - -/* 操作记录。*/ -$lang->bug->action->resolved = array('main' => '$date, Resolved by $actor, resolution is $extra.', 'extra' => $lang->bug->resolutionList); -$lang->bug->action->tostory = array('main' => '$date, To story by $actor, ID is $extra.'); -$lang->bug->action->totask = array('main' => '$date, To task by $actor, ID is $extra.'); + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +/* Fieldlist. */ +$lang->bug->common = 'Bug'; +$lang->bug->id = 'ID'; +$lang->bug->product = 'Product'; +$lang->bug->module = 'Module'; +$lang->bug->path = 'Path'; +$lang->bug->project = 'Project'; +$lang->bug->story = 'Story'; +$lang->bug->storyVersion = 'Story Version'; +$lang->bug->task = 'Task'; +$lang->bug->title = 'Title'; +$lang->bug->severity = 'Severity'; +$lang->bug->severityAB = 'S'; +$lang->bug->pri = 'Priority'; +$lang->bug->type = 'Type'; +$lang->bug->os = 'OS'; +$lang->bug->hardware = 'Hardware'; +$lang->bug->browser = 'Browser'; +$lang->bug->machine = 'Machine'; +$lang->bug->found = 'How found'; +$lang->bug->steps = 'Steps'; +$lang->bug->status = 'Status'; +$lang->bug->statusAB = 'Status'; +$lang->bug->activatedCount = 'Activated count'; +$lang->bug->activatedCountAB = 'Activated count'; +$lang->bug->confirmed = 'Confirmed'; +$lang->bug->toTask = 'To task'; +$lang->bug->toStory = 'To story'; +$lang->bug->mailto = 'Mailto'; +$lang->bug->openedBy = 'Opened By'; +$lang->bug->openedByAB = 'Opened'; +$lang->bug->openedDate = 'Opened date'; +$lang->bug->openedDateAB = 'Date'; +$lang->bug->openedBuild = 'Opened Build'; +$lang->bug->assignedTo = 'Assigned'; +$lang->bug->assignedDate = 'Assigned Date'; +$lang->bug->resolvedBy = 'Resolved By'; +$lang->bug->resolvedByAB = 'Resolve'; +$lang->bug->resolution = 'Resolution'; +$lang->bug->resolutionAB = 'Resolution'; +$lang->bug->resolvedBuild = 'Resolved Build'; +$lang->bug->resolvedDate = 'Resolved Date'; +$lang->bug->resolvedDateAB = 'Date'; +$lang->bug->closedBy = 'Closed By'; +$lang->bug->closedDate = 'Closed Date'; +$lang->bug->duplicateBug = 'Duplicate'; +$lang->bug->lastEditedBy = 'Last Edited By'; +$lang->bug->lastEditedDate = 'Last Edited Date'; +$lang->bug->linkBug = 'Related'; +$lang->bug->case = 'Case'; +$lang->bug->files = 'Files'; +$lang->bug->keywords = 'Keywords'; +$lang->bug->lastEditedByAB = 'Edited'; +$lang->bug->lastEditedDateAB = 'Edited Date'; + +/* Actions. */ +$lang->bug->index = 'Index'; +$lang->bug->create = 'Create Bug'; +$lang->bug->confirmBug = 'Confirm Bug'; +$lang->bug->edit = 'Edit Bug'; +$lang->bug->browse = 'Browse Bug'; +$lang->bug->view = 'Bug Info'; +$lang->bug->resolve = 'Resolve Bug'; +$lang->bug->close = 'Close Bug'; +$lang->bug->activate = 'Activate Bug'; +$lang->bug->reportChart = 'Report'; +$lang->bug->export = 'Export data'; +$lang->bug->delete = 'Delete Bug'; +$lang->bug->saveTemplate = 'Save template'; +$lang->bug->deleteTemplate = 'Delete template'; +$lang->bug->customFields = 'Custom'; +$lang->bug->restoreDefault = 'Default'; +$lang->bug->ajaxGetUserBugs = 'API: My Bugs'; +$lang->bug->ajaxGetModuleOwner = 'API: Get module default owner'; +$lang->bug->confirmStoryChange = 'Confirm Story Change'; + +/* Browse tabs. */ +$lang->bug->selectProduct = 'Select product'; +$lang->bug->byModule = 'ByModule'; +$lang->bug->assignToMe = 'MyBugs'; +$lang->bug->openedByMe = 'MyOpen'; +$lang->bug->resolvedByMe = 'MyResolve'; +$lang->bug->closedByMe = 'MyClose'; +$lang->bug->assignToNull = 'Unassigned'; +$lang->bug->unResolved = 'Unresolved'; +$lang->bug->unclosed = 'Unclosed'; +$lang->bug->longLifeBugs = 'Longlife'; +$lang->bug->postponedBugs = 'Postponed'; +$lang->bug->allBugs = 'Allbug'; +$lang->bug->moduleBugs = 'ByModule'; +$lang->bug->byQuery = 'Search'; +$lang->bug->needConfirm = 'StoryChanged'; +$lang->bug->allProduct = 'All products'; + +/* Labels. */ +$lang->bug->lblProductAndModule = 'Product&Module'; +$lang->bug->lblProjectAndTask = 'Project&Task'; +$lang->bug->lblStory = 'Story'; +$lang->bug->lblTypeAndSeverity = 'Type&Severity'; +$lang->bug->lblSystemBrowserAndHardware = 'OS&Browser'; +$lang->bug->lblAssignedTo = 'Assigned to'; +$lang->bug->lblMailto = 'Mailto'; +$lang->bug->lblLastEdited = 'Last edited'; +$lang->bug->lblResolved = 'Resolved'; +$lang->bug->lblAllFields = 'All Fields'; +$lang->bug->lblCustomFields = 'Custom Fields'; + +/* Legends. */ +$lang->bug->legendBasicInfo = 'Basic info'; +$lang->bug->legendMailto = 'Mailto'; +$lang->bug->legendAttatch = 'Files'; +$lang->bug->legendLinkBugs = 'Related bug'; +$lang->bug->legendPrjStoryTask = 'Project, story & task'; +$lang->bug->legendCases = 'Related case'; +$lang->bug->legendSteps = 'Steps'; +$lang->bug->legendAction = 'Action'; +$lang->bug->legendHistory = 'History'; +$lang->bug->legendComment = 'Comment'; +$lang->bug->legendLife = 'Lifetime'; +$lang->bug->legendMisc = 'Misc'; + +/* Action buttons. */ +$lang->bug->buttonConfirm = 'Confirm'; +$lang->bug->buttonCopy = 'Copy'; +$lang->bug->buttonEdit = 'Edit'; +$lang->bug->buttonActivate = 'Activate'; +$lang->bug->buttonResolve = 'Resolve'; +$lang->bug->buttonClose = 'Close'; +$lang->bug->buttonToList = 'Back'; +$lang->bug->buttonCreateTestcase = 'Create case'; + +/* Confirm messags. */ +$lang->bug->confirmChangeProduct = 'Change product will change project, task and story also, are you sure?'; +$lang->bug->confirmDelete = 'Are you sure to delete this bug?'; +$lang->bug->setTemplateTitle = 'Please input the template title:'; +$lang->bug->remindTask = 'This bug has been to be a task, update the task:%s or not?'; + +/* Templates. */ +$lang->bug->tplStep = "

[Steps]

"; +$lang->bug->tplResult = "

[Result]

"; +$lang->bug->tplExpect = "

[Expect]

"; + +/* Field options lists. */ +$lang->bug->severityList[3] = '3'; +$lang->bug->severityList[1] = '1'; +$lang->bug->severityList[2] = '2'; +$lang->bug->severityList[4] = '4'; + +$lang->bug->priList[0] = ''; +$lang->bug->priList[3] = '3'; +$lang->bug->priList[1] = '1'; +$lang->bug->priList[2] = '2'; +$lang->bug->priList[4] = '4'; + +$lang->bug->osList[''] = ''; +$lang->bug->osList['all'] = 'All'; +$lang->bug->osList['windows'] = 'Windows'; +$lang->bug->osList['winxp'] = 'Windows XP'; +$lang->bug->osList['win7'] = 'Windows 7'; +$lang->bug->osList['vista'] = 'Windows Vista'; +$lang->bug->osList['win2000'] = 'Windows 2000'; +$lang->bug->osList['win2003'] = 'Windows 2003'; +$lang->bug->osList['win2008'] = 'Windows 2008'; +$lang->bug->osList['winnt'] = 'Windows NT'; +$lang->bug->osList['win98'] = 'Windows 98'; +$lang->bug->osList['andriod'] = 'Andriod'; +$lang->bug->osList['ios'] = 'IOS'; +$lang->bug->osList['wp7'] = 'WP7'; +$lang->bug->osList['symbian'] = 'Symbian'; +$lang->bug->osList['linux'] = 'Linux'; +$lang->bug->osList['freebsd'] = 'FreeBSD'; +$lang->bug->osList['mac'] = 'Mac OS'; +$lang->bug->osList['unix'] = 'Unix'; +$lang->bug->osList['others'] = 'Others'; + +$lang->bug->browserList[''] = ''; +$lang->bug->browserList['all'] = 'All'; +$lang->bug->browserList['ie'] = 'IE'; +$lang->bug->browserList['ie8'] = 'IE8'; +$lang->bug->browserList['ie9'] = 'IE9'; +$lang->bug->browserList['ie6'] = 'IE6'; +$lang->bug->browserList['ie7'] = 'IE7'; +$lang->bug->browserList['chrome'] = 'chrome'; +$lang->bug->browserList['firefox'] = 'Firefox'; +$lang->bug->browserList['firefox2'] = 'Firefox2'; +$lang->bug->browserList['firefox3'] = 'Firefox3'; +$lang->bug->browserList['firefox4'] = 'Firefox4'; +$lang->bug->browserList['opera'] = 'opera'; +$lang->bug->browserList['opera9'] = 'opera9'; +$lang->bug->browserList['oprea10'] = 'opera10'; +$lang->bug->browserList['oprea11'] = 'opera11'; +$lang->bug->browserList['safari'] = 'safari'; +$lang->bug->browserList['maxthon'] = '傲游'; +$lang->bug->browserList['uc'] = 'UC'; +$lang->bug->browserList['other'] = 'Others'; + +$lang->bug->typeList[''] = ''; +$lang->bug->typeList['codeerror'] = 'Code error'; +$lang->bug->typeList['interface'] = 'Interface'; +$lang->bug->typeList['designchange'] = 'Design change'; +$lang->bug->typeList['newfeature'] = 'New feature'; +$lang->bug->typeList['designdefect'] = 'Design defect'; +$lang->bug->typeList['config'] = 'Config'; +$lang->bug->typeList['install'] = 'Install'; +$lang->bug->typeList['security'] = 'Security'; +$lang->bug->typeList['performance'] = 'Performance'; +$lang->bug->typeList['standard'] = 'Standard'; +$lang->bug->typeList['automation'] = 'Automation'; +$lang->bug->typeList['trackthings'] = 'Tracking'; +$lang->bug->typeList['others'] = 'Others'; + +$lang->bug->statusList[''] = ''; +$lang->bug->statusList['active'] = 'Active'; +$lang->bug->statusList['resolved'] = 'Resolved'; +$lang->bug->statusList['closed'] = 'Closed'; + +$lang->bug->confirmedList[1] = 'Confirmed'; +$lang->bug->confirmedList[0] = 'Unconfirmed'; + +$lang->bug->resolutionList[''] = ''; +$lang->bug->resolutionList['bydesign'] = 'By design'; +$lang->bug->resolutionList['duplicate'] = 'Duplicate'; +$lang->bug->resolutionList['external'] = 'External'; +$lang->bug->resolutionList['fixed'] = 'Fixed'; +$lang->bug->resolutionList['notrepro'] = 'Not reproduce'; +$lang->bug->resolutionList['postponed'] = 'Postponed'; +$lang->bug->resolutionList['willnotfix'] = "Won't fix"; +$lang->bug->resolutionList['tostory'] = 'To story'; + +/* Report. */ +$lang->bug->report->common = 'Report'; +$lang->bug->report->select = 'Select'; +$lang->bug->report->create = 'Create'; +$lang->bug->report->selectAll = 'All'; +$lang->bug->report->selectReverse = 'Reverse'; + +$lang->bug->report->charts['bugsPerProject'] = 'Project bugs'; +$lang->bug->report->charts['bugsPerModule'] = 'Module bugs'; +$lang->bug->report->charts['openedBugsPerDay'] = 'Opened bugs per day'; +$lang->bug->report->charts['resolvedBugsPerDay'] = 'Resolved bugs per day'; +$lang->bug->report->charts['closedBugsPerDay'] = 'Closed bugs per day'; +$lang->bug->report->charts['openedBugsPerUser'] = 'Opened bugs per user'; +$lang->bug->report->charts['resolvedBugsPerUser'] = 'Resolved bugs per user'; +$lang->bug->report->charts['closedBugsPerUser'] = 'Closed bugs per user'; +$lang->bug->report->charts['bugsPerSeverity'] = 'Severity'; +$lang->bug->report->charts['bugsPerResolution'] = 'Resolution'; +$lang->bug->report->charts['bugsPerStatus'] = 'Status'; +$lang->bug->report->charts['bugsPerActivatedCount'] = 'Activated count'; +$lang->bug->report->charts['bugsPerType'] = 'Type'; +$lang->bug->report->charts['bugsPerAssignedTo'] = 'AssignedTo'; +//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计'; +//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计'; + +$lang->bug->report->options->swf = 'pie2d'; +$lang->bug->report->options->width = 'auto'; +$lang->bug->report->options->height = 300; +$lang->bug->report->options->graph->baseFontSize = 12; +$lang->bug->report->options->graph->showNames = 1; +$lang->bug->report->options->graph->formatNumber = 1; +$lang->bug->report->options->graph->decimalPrecision = 0; +$lang->bug->report->options->graph->animation = 0; +$lang->bug->report->options->graph->rotateNames = 0; +$lang->bug->report->options->graph->yAxisName = 'COUNT'; +$lang->bug->report->options->graph->pieRadius = 100; +$lang->bug->report->options->graph->showColumnShadow = 0; + +$lang->bug->report->bugsPerProject->graph->xAxisName = 'Project'; +$lang->bug->report->bugsPerModule->graph->xAxisName = 'Module'; + +$lang->bug->report->openedBugsPerDay->swf = 'column2d'; +$lang->bug->report->openedBugsPerDay->height = 400; +$lang->bug->report->openedBugsPerDay->graph->xAxisName = 'Date'; +$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; +$lang->bug->report->resolvedBugsPerDay->height = 400; +$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = 'Date'; +$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->closedBugsPerDay->swf = 'column2d'; +$lang->bug->report->closedBugsPerDay->height = 400; +$lang->bug->report->closedBugsPerDay->graph->xAxisName = 'Date'; +$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->openedBugsPerUser->graph->xAxisName = 'User'; +$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= 'User'; +$lang->bug->report->closedBugsPerUser->graph->xAxisName = 'User'; + +$lang->bug->report->bugsPerSeverity->graph->xAxisName = 'Severity'; +$lang->bug->report->bugsPerResolution->graph->xAxisName = 'Resolution'; +$lang->bug->report->bugsPerStatus->graph->xAxisName = 'Status'; +$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = 'Activated count'; +$lang->bug->report->bugsPerType->graph->xAxisName = 'Type'; +$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = 'AssignedTo'; +$lang->bug->report->bugLiveDays->graph->xAxisName = 'Live days'; +$lang->bug->report->bugHistories->graph->xAxisName = 'Histories'; + +/* 操作记录。*/ +$lang->bug->action->resolved = array('main' => '$date, Resolved by $actor, resolution is $extra.', 'extra' => $lang->bug->resolutionList); +$lang->bug->action->tostory = array('main' => '$date, To story by $actor, ID is $extra.'); +$lang->bug->action->totask = array('main' => '$date, To task by $actor, ID is $extra.'); diff --git a/module/bug/lang/zh-cn.php b/module/bug/lang/zh-cn.php index fd5f8ab6d2..1441d1b7f9 100644 --- a/module/bug/lang/zh-cn.php +++ b/module/bug/lang/zh-cn.php @@ -1,312 +1,312 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -/* 字段列表。*/ -$lang->bug->common = '缺陷管理'; -$lang->bug->id = 'Bug编号'; -$lang->bug->product = '所属产品'; -$lang->bug->module = '所属模块'; -$lang->bug->path = '模块路径'; -$lang->bug->project = '所属项目'; -$lang->bug->story = '相关需求'; -$lang->bug->storyVersion = '需求版本'; -$lang->bug->task = '相关任务'; -$lang->bug->title = 'Bug标题'; -$lang->bug->severity = '严重程度'; -$lang->bug->severityAB = '级别'; -$lang->bug->pri = '优先级'; -$lang->bug->type = 'Bug类型'; -$lang->bug->os = '操作系统'; -$lang->bug->hardware = '硬件平台'; -$lang->bug->browser = '浏览器'; -$lang->bug->machine = '机器硬件'; -$lang->bug->found = '如何发现'; -$lang->bug->steps = '重现步骤'; -$lang->bug->status = 'Bug状态'; -$lang->bug->statusAB = '状态'; -$lang->bug->activatedCount = '激活次数'; -$lang->bug->activatedCountAB = '激活次数'; -$lang->bug->confirmed = '是否确认'; -$lang->bug->toTask = '转任务'; -$lang->bug->toStory = '转需求'; -$lang->bug->mailto = '抄送给'; -$lang->bug->openedBy = '由谁创建'; -$lang->bug->openedByAB = '创建'; -$lang->bug->openedDate = '创建日期'; -$lang->bug->openedDateAB = '创建日期'; -$lang->bug->openedBuild = '影响版本'; -$lang->bug->assignedTo = '指派给'; -$lang->bug->assignedDate = '指派日期'; -$lang->bug->resolvedBy = '解决者'; -$lang->bug->resolvedByAB = '解决'; -$lang->bug->resolution = '解决方案'; -$lang->bug->resolutionAB = '方案'; -$lang->bug->resolvedBuild = '解决版本'; -$lang->bug->resolvedDate = '解决日期'; -$lang->bug->resolvedDateAB = '解决日期'; -$lang->bug->closedBy = '由谁关闭'; -$lang->bug->closedDate = '关闭日期'; -$lang->bug->duplicateBug = '重复Bug'; -$lang->bug->lastEditedBy = '最后修改者'; -$lang->bug->lastEditedDate = '最后修改日期'; -$lang->bug->linkBug = '相关Bug'; -$lang->bug->case = '相关用例'; -$lang->bug->files = '附件'; -$lang->bug->keywords = '关键词'; -$lang->bug->lastEditedByAB = '修改者'; -$lang->bug->lastEditedDateAB = '修改日期'; - -/* 方法列表。*/ -$lang->bug->index = '首页'; -$lang->bug->create = '创建Bug'; -$lang->bug->confirmBug = '确认'; -$lang->bug->edit = '编辑Bug'; -$lang->bug->browse = 'Bug列表'; -$lang->bug->view = 'Bug详情'; -$lang->bug->resolve = '解决Bug'; -$lang->bug->close = '关闭Bug'; -$lang->bug->activate = '激活Bug'; -$lang->bug->reportChart = '报表统计'; -$lang->bug->export = '导出数据'; -$lang->bug->delete = '删除Bug'; -$lang->bug->saveTemplate = '保存模板'; -$lang->bug->deleteTemplate = '删除模板'; -$lang->bug->customFields = '自定义字段'; -$lang->bug->restoreDefault = '恢复默认'; -$lang->bug->ajaxGetUserBugs = '接口:我的Bug'; -$lang->bug->ajaxGetModuleOwner = '接口:获得模块的默认指派人'; -$lang->bug->confirmStoryChange = '确认需求变动'; - -/* 查询条件列表。*/ -$lang->bug->selectProduct = '请选择产品'; -$lang->bug->byModule = '按模块'; -$lang->bug->assignToMe = '指派给我'; -$lang->bug->openedByMe = '由我创建'; -$lang->bug->resolvedByMe = '由我解决'; -$lang->bug->closedByMe = '由我关闭'; -$lang->bug->assignToNull = '未指派'; -$lang->bug->unResolved = '未解决'; -$lang->bug->unclosed = '未关闭'; -$lang->bug->longLifeBugs = '久未处理'; -$lang->bug->postponedBugs = '被延期'; -$lang->bug->allBugs = '所有Bug'; -$lang->bug->moduleBugs = '按模块浏览'; -$lang->bug->byQuery = '搜索'; -$lang->bug->needConfirm = '需求变动'; -$lang->bug->allProduct = '所有产品'; - -/* 页面标签。*/ -$lang->bug->lblProductAndModule = '产品模块'; -$lang->bug->lblProjectAndTask = '项目任务'; -$lang->bug->lblStory = '相关需求'; -$lang->bug->lblTypeAndSeverity = '类型/严重程度'; -$lang->bug->lblSystemBrowserAndHardware = '系统/浏览器'; -$lang->bug->lblAssignedTo = '当前指派'; -$lang->bug->lblMailto = '抄送给'; -$lang->bug->lblLastEdited = '最后修改'; -$lang->bug->lblResolved = '由谁解决'; -$lang->bug->lblAllFields = '所有字段'; -$lang->bug->lblCustomFields = '自定义字段'; - -/* legend列表。*/ -$lang->bug->legendBasicInfo = '基本信息'; -$lang->bug->legendMailto = '抄送给'; -$lang->bug->legendAttatch = '附件'; -$lang->bug->legendLinkBugs = '相关Bug'; -$lang->bug->legendPrjStoryTask = '项目/需求/任务'; -$lang->bug->legendCases = '相关用例'; -$lang->bug->legendSteps = '重现步骤'; -$lang->bug->legendAction = '操作'; -$lang->bug->legendHistory = '历史记录'; -$lang->bug->legendComment = '备注'; -$lang->bug->legendLife = 'BUG的一生'; -$lang->bug->legendMisc = '其相关他'; - -/* 功能按钮。*/ -$lang->bug->buttonConfirm = '确认'; -$lang->bug->buttonCopy = '复制'; -$lang->bug->buttonEdit = '编辑'; -$lang->bug->buttonActivate = '激活'; -$lang->bug->buttonResolve = '解决'; -$lang->bug->buttonClose = '关闭'; -$lang->bug->buttonToList = '返回'; -$lang->bug->buttonCreateTestcase = '建用例'; - -/* 交互提示。*/ -$lang->bug->confirmChangeProduct = '修改产品会导致相应的项目、需求和任务发生变化,确定吗?'; -$lang->bug->confirmDelete = '您确认要删除该Bug吗?'; -$lang->bug->setTemplateTitle = '请输入bug模板标题(保存之前请先填写bug重现步骤):'; -$lang->bug->remindTask = '该Bug已经转化为任务,是否更新任务(编号:%s)状态 ?'; - -/* 模板。*/ -$lang->bug->tplStep = "

[步骤]

"; -$lang->bug->tplResult = "

[结果]

"; -$lang->bug->tplExpect = "

[期望]

"; - -/* 各个字段取值列表。*/ -$lang->bug->severityList[3] = '3'; -$lang->bug->severityList[1] = '1'; -$lang->bug->severityList[2] = '2'; -$lang->bug->severityList[4] = '4'; - -$lang->bug->priList[0] = ''; -$lang->bug->priList[3] = '3'; -$lang->bug->priList[1] = '1'; -$lang->bug->priList[2] = '2'; -$lang->bug->priList[4] = '4'; - -$lang->bug->osList[''] = ''; -$lang->bug->osList['all'] = '全部'; -$lang->bug->osList['windows'] = 'Windows'; -$lang->bug->osList['winxp'] = 'Windows XP'; -$lang->bug->osList['win7'] = 'Windows 7'; -$lang->bug->osList['vista'] = 'Windows Vista'; -$lang->bug->osList['win2000'] = 'Windows 2000'; -$lang->bug->osList['win2003'] = 'Windows 2003'; -$lang->bug->osList['win2008'] = 'Windows 2008'; -$lang->bug->osList['winnt'] = 'Windows NT'; -$lang->bug->osList['win98'] = 'Windows 98'; -$lang->bug->osList['andriod'] = 'Andriod'; -$lang->bug->osList['ios'] = 'IOS'; -$lang->bug->osList['wp7'] = 'WP7'; -$lang->bug->osList['symbian'] = 'Symbian'; -$lang->bug->osList['linux'] = 'Linux'; -$lang->bug->osList['freebsd'] = 'FreeBSD'; -$lang->bug->osList['mac'] = 'Mac OS'; -$lang->bug->osList['unix'] = 'Unix'; -$lang->bug->osList['others'] = '其他'; - -$lang->bug->browserList[''] = ''; -$lang->bug->browserList['all'] = '全部'; -$lang->bug->browserList['ie'] = 'IE系列'; -$lang->bug->browserList['ie8'] = 'IE8'; -$lang->bug->browserList['ie9'] = 'IE9'; -$lang->bug->browserList['ie6'] = 'IE6'; -$lang->bug->browserList['ie7'] = 'IE7'; -$lang->bug->browserList['chrome'] = 'chrome'; -$lang->bug->browserList['firefox'] = 'firefox系列'; -$lang->bug->browserList['firefox2'] = 'firefox2'; -$lang->bug->browserList['firefox3'] = 'firefox3'; -$lang->bug->browserList['firefox4'] = 'firefox4'; -$lang->bug->browserList['opera'] = 'opera系列'; -$lang->bug->browserList['opera9'] = 'opera9'; -$lang->bug->browserList['oprea10'] = 'opera10'; -$lang->bug->browserList['oprea11'] = 'opera11'; -$lang->bug->browserList['safari'] = 'safari'; -$lang->bug->browserList['maxthon'] = '傲游'; -$lang->bug->browserList['uc'] = 'UC'; -$lang->bug->browserList['other'] = '其他'; - -$lang->bug->typeList[''] = ''; -$lang->bug->typeList['codeerror'] = '代码错误'; -$lang->bug->typeList['interface'] = '界面优化'; -$lang->bug->typeList['designchange'] = '设计变更'; -$lang->bug->typeList['newfeature'] = '新增需求'; -$lang->bug->typeList['designdefect'] = '设计缺陷'; -$lang->bug->typeList['config'] = '配置相关'; -$lang->bug->typeList['install'] = '安装部署'; -$lang->bug->typeList['security'] = '安全相关'; -$lang->bug->typeList['performance'] = '性能问题'; -$lang->bug->typeList['standard'] = '标准规范'; -$lang->bug->typeList['automation'] = '测试脚本'; -$lang->bug->typeList['trackthings'] = '事务跟踪'; -$lang->bug->typeList['others'] = '其他'; - -$lang->bug->statusList[''] = ''; -$lang->bug->statusList['active'] = '激活'; -$lang->bug->statusList['resolved'] = '已解决'; -$lang->bug->statusList['closed'] = '已关闭'; - -$lang->bug->confirmedList[1] = '已确认'; -$lang->bug->confirmedList[0] = '未确认'; - -$lang->bug->resolutionList[''] = ''; -$lang->bug->resolutionList['bydesign'] = '设计如此'; -$lang->bug->resolutionList['duplicate'] = '重复Bug'; -$lang->bug->resolutionList['external'] = '外部原因'; -$lang->bug->resolutionList['fixed'] = '已解决'; -$lang->bug->resolutionList['notrepro'] = '无法重现'; -$lang->bug->resolutionList['postponed'] = '延期处理'; -$lang->bug->resolutionList['willnotfix'] = "不予解决"; -$lang->bug->resolutionList['tostory'] = '转为需求'; - -/* 统计报表。*/ -$lang->bug->report->common = '统计报表'; -$lang->bug->report->select = '请选择报表类型'; -$lang->bug->report->create = '生成报表'; -$lang->bug->report->selectAll = '全选'; -$lang->bug->report->selectReverse = '反选'; - -$lang->bug->report->charts['bugsPerProject'] = '项目Bug数量'; -$lang->bug->report->charts['bugsPerModule'] = '模块Bug数量'; -$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug数'; -$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解决Bug数'; -$lang->bug->report->charts['closedBugsPerDay'] = '每天关闭的Bug数'; -$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug数'; -$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解决的Bug数'; -$lang->bug->report->charts['closedBugsPerUser'] = '每人关闭的Bug数'; -$lang->bug->report->charts['bugsPerSeverity'] = 'Bug严重程度统计'; -$lang->bug->report->charts['bugsPerResolution'] = 'Bug解决方案统计'; -$lang->bug->report->charts['bugsPerStatus'] = 'Bug状态统计'; -$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次数统计'; -$lang->bug->report->charts['bugsPerType'] = 'Bug类型统计'; -$lang->bug->report->charts['bugsPerAssignedTo'] = '指派给统计'; -//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计'; -//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计'; - -$lang->bug->report->options->swf = 'pie2d'; -$lang->bug->report->options->width = 'auto'; -$lang->bug->report->options->height = 300; -$lang->bug->report->options->graph->baseFontSize = 12; -$lang->bug->report->options->graph->showNames = 1; -$lang->bug->report->options->graph->formatNumber = 1; -$lang->bug->report->options->graph->decimalPrecision = 0; -$lang->bug->report->options->graph->animation = 0; -$lang->bug->report->options->graph->rotateNames = 0; -$lang->bug->report->options->graph->yAxisName = 'COUNT'; -$lang->bug->report->options->graph->pieRadius = 100; // 饼图直径。 -$lang->bug->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 - -$lang->bug->report->bugsPerProject->graph->xAxisName = '项目'; -$lang->bug->report->bugsPerModule->graph->xAxisName = '模块'; - -$lang->bug->report->openedBugsPerDay->swf = 'column2d'; -$lang->bug->report->openedBugsPerDay->height = 400; -$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; -$lang->bug->report->resolvedBugsPerDay->height = 400; -$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->closedBugsPerDay->swf = 'column2d'; -$lang->bug->report->closedBugsPerDay->height = 400; -$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用户'; -$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用户'; -$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用户'; - -$lang->bug->report->bugsPerSeverity->graph->xAxisName = '严重程度'; -$lang->bug->report->bugsPerResolution->graph->xAxisName = '解决方案'; -$lang->bug->report->bugsPerStatus->graph->xAxisName = '状态'; -$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次数'; -$lang->bug->report->bugsPerType->graph->xAxisName = '类型'; -$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派给'; -$lang->bug->report->bugLiveDays->graph->xAxisName = '处理时间'; -$lang->bug->report->bugHistories->graph->xAxisName = '处理步骤'; - -/* 操作记录。*/ -$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解决,方案为 $extra。', 'extra' => $lang->bug->resolutionList); -$lang->bug->action->tostory = array('main' => '$date, 由 $actor 转为需求,编号为 $extra。'); -$lang->bug->action->totask = array('main' => '$date, 由 $actor 导入为任务,编号为 $extra。'); + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +/* 字段列表。*/ +$lang->bug->common = '缺陷管理'; +$lang->bug->id = 'Bug编号'; +$lang->bug->product = '所属产品'; +$lang->bug->module = '所属模块'; +$lang->bug->path = '模块路径'; +$lang->bug->project = '所属项目'; +$lang->bug->story = '相关需求'; +$lang->bug->storyVersion = '需求版本'; +$lang->bug->task = '相关任务'; +$lang->bug->title = 'Bug标题'; +$lang->bug->severity = '严重程度'; +$lang->bug->severityAB = '级别'; +$lang->bug->pri = '优先级'; +$lang->bug->type = 'Bug类型'; +$lang->bug->os = '操作系统'; +$lang->bug->hardware = '硬件平台'; +$lang->bug->browser = '浏览器'; +$lang->bug->machine = '机器硬件'; +$lang->bug->found = '如何发现'; +$lang->bug->steps = '重现步骤'; +$lang->bug->status = 'Bug状态'; +$lang->bug->statusAB = '状态'; +$lang->bug->activatedCount = '激活次数'; +$lang->bug->activatedCountAB = '激活次数'; +$lang->bug->confirmed = '是否确认'; +$lang->bug->toTask = '转任务'; +$lang->bug->toStory = '转需求'; +$lang->bug->mailto = '抄送给'; +$lang->bug->openedBy = '由谁创建'; +$lang->bug->openedByAB = '创建'; +$lang->bug->openedDate = '创建日期'; +$lang->bug->openedDateAB = '创建日期'; +$lang->bug->openedBuild = '影响版本'; +$lang->bug->assignedTo = '指派给'; +$lang->bug->assignedDate = '指派日期'; +$lang->bug->resolvedBy = '解决者'; +$lang->bug->resolvedByAB = '解决'; +$lang->bug->resolution = '解决方案'; +$lang->bug->resolutionAB = '方案'; +$lang->bug->resolvedBuild = '解决版本'; +$lang->bug->resolvedDate = '解决日期'; +$lang->bug->resolvedDateAB = '解决日期'; +$lang->bug->closedBy = '由谁关闭'; +$lang->bug->closedDate = '关闭日期'; +$lang->bug->duplicateBug = '重复Bug'; +$lang->bug->lastEditedBy = '最后修改者'; +$lang->bug->lastEditedDate = '最后修改日期'; +$lang->bug->linkBug = '相关Bug'; +$lang->bug->case = '相关用例'; +$lang->bug->files = '附件'; +$lang->bug->keywords = '关键词'; +$lang->bug->lastEditedByAB = '修改者'; +$lang->bug->lastEditedDateAB = '修改日期'; + +/* 方法列表。*/ +$lang->bug->index = '首页'; +$lang->bug->create = '创建Bug'; +$lang->bug->confirmBug = '确认'; +$lang->bug->edit = '编辑Bug'; +$lang->bug->browse = 'Bug列表'; +$lang->bug->view = 'Bug详情'; +$lang->bug->resolve = '解决Bug'; +$lang->bug->close = '关闭Bug'; +$lang->bug->activate = '激活Bug'; +$lang->bug->reportChart = '报表统计'; +$lang->bug->export = '导出数据'; +$lang->bug->delete = '删除Bug'; +$lang->bug->saveTemplate = '保存模板'; +$lang->bug->deleteTemplate = '删除模板'; +$lang->bug->customFields = '自定义字段'; +$lang->bug->restoreDefault = '恢复默认'; +$lang->bug->ajaxGetUserBugs = '接口:我的Bug'; +$lang->bug->ajaxGetModuleOwner = '接口:获得模块的默认指派人'; +$lang->bug->confirmStoryChange = '确认需求变动'; + +/* 查询条件列表。*/ +$lang->bug->selectProduct = '请选择产品'; +$lang->bug->byModule = '按模块'; +$lang->bug->assignToMe = '指派给我'; +$lang->bug->openedByMe = '由我创建'; +$lang->bug->resolvedByMe = '由我解决'; +$lang->bug->closedByMe = '由我关闭'; +$lang->bug->assignToNull = '未指派'; +$lang->bug->unResolved = '未解决'; +$lang->bug->unclosed = '未关闭'; +$lang->bug->longLifeBugs = '久未处理'; +$lang->bug->postponedBugs = '被延期'; +$lang->bug->allBugs = '所有Bug'; +$lang->bug->moduleBugs = '按模块浏览'; +$lang->bug->byQuery = '搜索'; +$lang->bug->needConfirm = '需求变动'; +$lang->bug->allProduct = '所有产品'; + +/* 页面标签。*/ +$lang->bug->lblProductAndModule = '产品模块'; +$lang->bug->lblProjectAndTask = '项目任务'; +$lang->bug->lblStory = '相关需求'; +$lang->bug->lblTypeAndSeverity = '类型/严重程度'; +$lang->bug->lblSystemBrowserAndHardware = '系统/浏览器'; +$lang->bug->lblAssignedTo = '当前指派'; +$lang->bug->lblMailto = '抄送给'; +$lang->bug->lblLastEdited = '最后修改'; +$lang->bug->lblResolved = '由谁解决'; +$lang->bug->lblAllFields = '所有字段'; +$lang->bug->lblCustomFields = '自定义字段'; + +/* legend列表。*/ +$lang->bug->legendBasicInfo = '基本信息'; +$lang->bug->legendMailto = '抄送给'; +$lang->bug->legendAttatch = '附件'; +$lang->bug->legendLinkBugs = '相关Bug'; +$lang->bug->legendPrjStoryTask = '项目/需求/任务'; +$lang->bug->legendCases = '相关用例'; +$lang->bug->legendSteps = '重现步骤'; +$lang->bug->legendAction = '操作'; +$lang->bug->legendHistory = '历史记录'; +$lang->bug->legendComment = '备注'; +$lang->bug->legendLife = 'BUG的一生'; +$lang->bug->legendMisc = '其相关他'; + +/* 功能按钮。*/ +$lang->bug->buttonConfirm = '确认'; +$lang->bug->buttonCopy = '复制'; +$lang->bug->buttonEdit = '编辑'; +$lang->bug->buttonActivate = '激活'; +$lang->bug->buttonResolve = '解决'; +$lang->bug->buttonClose = '关闭'; +$lang->bug->buttonToList = '返回'; +$lang->bug->buttonCreateTestcase = '建用例'; + +/* 交互提示。*/ +$lang->bug->confirmChangeProduct = '修改产品会导致相应的项目、需求和任务发生变化,确定吗?'; +$lang->bug->confirmDelete = '您确认要删除该Bug吗?'; +$lang->bug->setTemplateTitle = '请输入bug模板标题(保存之前请先填写bug重现步骤):'; +$lang->bug->remindTask = '该Bug已经转化为任务,是否更新任务(编号:%s)状态 ?'; + +/* 模板。*/ +$lang->bug->tplStep = "

[步骤]

"; +$lang->bug->tplResult = "

[结果]

"; +$lang->bug->tplExpect = "

[期望]

"; + +/* 各个字段取值列表。*/ +$lang->bug->severityList[3] = '3'; +$lang->bug->severityList[1] = '1'; +$lang->bug->severityList[2] = '2'; +$lang->bug->severityList[4] = '4'; + +$lang->bug->priList[0] = ''; +$lang->bug->priList[3] = '3'; +$lang->bug->priList[1] = '1'; +$lang->bug->priList[2] = '2'; +$lang->bug->priList[4] = '4'; + +$lang->bug->osList[''] = ''; +$lang->bug->osList['all'] = '全部'; +$lang->bug->osList['windows'] = 'Windows'; +$lang->bug->osList['winxp'] = 'Windows XP'; +$lang->bug->osList['win7'] = 'Windows 7'; +$lang->bug->osList['vista'] = 'Windows Vista'; +$lang->bug->osList['win2000'] = 'Windows 2000'; +$lang->bug->osList['win2003'] = 'Windows 2003'; +$lang->bug->osList['win2008'] = 'Windows 2008'; +$lang->bug->osList['winnt'] = 'Windows NT'; +$lang->bug->osList['win98'] = 'Windows 98'; +$lang->bug->osList['andriod'] = 'Andriod'; +$lang->bug->osList['ios'] = 'IOS'; +$lang->bug->osList['wp7'] = 'WP7'; +$lang->bug->osList['symbian'] = 'Symbian'; +$lang->bug->osList['linux'] = 'Linux'; +$lang->bug->osList['freebsd'] = 'FreeBSD'; +$lang->bug->osList['mac'] = 'Mac OS'; +$lang->bug->osList['unix'] = 'Unix'; +$lang->bug->osList['others'] = '其他'; + +$lang->bug->browserList[''] = ''; +$lang->bug->browserList['all'] = '全部'; +$lang->bug->browserList['ie'] = 'IE系列'; +$lang->bug->browserList['ie8'] = 'IE8'; +$lang->bug->browserList['ie9'] = 'IE9'; +$lang->bug->browserList['ie6'] = 'IE6'; +$lang->bug->browserList['ie7'] = 'IE7'; +$lang->bug->browserList['chrome'] = 'chrome'; +$lang->bug->browserList['firefox'] = 'firefox系列'; +$lang->bug->browserList['firefox2'] = 'firefox2'; +$lang->bug->browserList['firefox3'] = 'firefox3'; +$lang->bug->browserList['firefox4'] = 'firefox4'; +$lang->bug->browserList['opera'] = 'opera系列'; +$lang->bug->browserList['opera9'] = 'opera9'; +$lang->bug->browserList['oprea10'] = 'opera10'; +$lang->bug->browserList['oprea11'] = 'opera11'; +$lang->bug->browserList['safari'] = 'safari'; +$lang->bug->browserList['maxthon'] = '傲游'; +$lang->bug->browserList['uc'] = 'UC'; +$lang->bug->browserList['other'] = '其他'; + +$lang->bug->typeList[''] = ''; +$lang->bug->typeList['codeerror'] = '代码错误'; +$lang->bug->typeList['interface'] = '界面优化'; +$lang->bug->typeList['designchange'] = '设计变更'; +$lang->bug->typeList['newfeature'] = '新增需求'; +$lang->bug->typeList['designdefect'] = '设计缺陷'; +$lang->bug->typeList['config'] = '配置相关'; +$lang->bug->typeList['install'] = '安装部署'; +$lang->bug->typeList['security'] = '安全相关'; +$lang->bug->typeList['performance'] = '性能问题'; +$lang->bug->typeList['standard'] = '标准规范'; +$lang->bug->typeList['automation'] = '测试脚本'; +$lang->bug->typeList['trackthings'] = '事务跟踪'; +$lang->bug->typeList['others'] = '其他'; + +$lang->bug->statusList[''] = ''; +$lang->bug->statusList['active'] = '激活'; +$lang->bug->statusList['resolved'] = '已解决'; +$lang->bug->statusList['closed'] = '已关闭'; + +$lang->bug->confirmedList[1] = '已确认'; +$lang->bug->confirmedList[0] = '未确认'; + +$lang->bug->resolutionList[''] = ''; +$lang->bug->resolutionList['bydesign'] = '设计如此'; +$lang->bug->resolutionList['duplicate'] = '重复Bug'; +$lang->bug->resolutionList['external'] = '外部原因'; +$lang->bug->resolutionList['fixed'] = '已解决'; +$lang->bug->resolutionList['notrepro'] = '无法重现'; +$lang->bug->resolutionList['postponed'] = '延期处理'; +$lang->bug->resolutionList['willnotfix'] = "不予解决"; +$lang->bug->resolutionList['tostory'] = '转为需求'; + +/* 统计报表。*/ +$lang->bug->report->common = '统计报表'; +$lang->bug->report->select = '请选择报表类型'; +$lang->bug->report->create = '生成报表'; +$lang->bug->report->selectAll = '全选'; +$lang->bug->report->selectReverse = '反选'; + +$lang->bug->report->charts['bugsPerProject'] = '项目Bug数量'; +$lang->bug->report->charts['bugsPerModule'] = '模块Bug数量'; +$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug数'; +$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解决Bug数'; +$lang->bug->report->charts['closedBugsPerDay'] = '每天关闭的Bug数'; +$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug数'; +$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解决的Bug数'; +$lang->bug->report->charts['closedBugsPerUser'] = '每人关闭的Bug数'; +$lang->bug->report->charts['bugsPerSeverity'] = 'Bug严重程度统计'; +$lang->bug->report->charts['bugsPerResolution'] = 'Bug解决方案统计'; +$lang->bug->report->charts['bugsPerStatus'] = 'Bug状态统计'; +$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次数统计'; +$lang->bug->report->charts['bugsPerType'] = 'Bug类型统计'; +$lang->bug->report->charts['bugsPerAssignedTo'] = '指派给统计'; +//$lang->bug->report->charts['bugLiveDays'] = 'Bug处理时间统计'; +//$lang->bug->report->charts['bugHistories'] = 'Bug处理步骤统计'; + +$lang->bug->report->options->swf = 'pie2d'; +$lang->bug->report->options->width = 'auto'; +$lang->bug->report->options->height = 300; +$lang->bug->report->options->graph->baseFontSize = 12; +$lang->bug->report->options->graph->showNames = 1; +$lang->bug->report->options->graph->formatNumber = 1; +$lang->bug->report->options->graph->decimalPrecision = 0; +$lang->bug->report->options->graph->animation = 0; +$lang->bug->report->options->graph->rotateNames = 0; +$lang->bug->report->options->graph->yAxisName = 'COUNT'; +$lang->bug->report->options->graph->pieRadius = 100; // 饼图直径。 +$lang->bug->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 + +$lang->bug->report->bugsPerProject->graph->xAxisName = '项目'; +$lang->bug->report->bugsPerModule->graph->xAxisName = '模块'; + +$lang->bug->report->openedBugsPerDay->swf = 'column2d'; +$lang->bug->report->openedBugsPerDay->height = 400; +$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; +$lang->bug->report->resolvedBugsPerDay->height = 400; +$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->closedBugsPerDay->swf = 'column2d'; +$lang->bug->report->closedBugsPerDay->height = 400; +$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用户'; +$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用户'; +$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用户'; + +$lang->bug->report->bugsPerSeverity->graph->xAxisName = '严重程度'; +$lang->bug->report->bugsPerResolution->graph->xAxisName = '解决方案'; +$lang->bug->report->bugsPerStatus->graph->xAxisName = '状态'; +$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次数'; +$lang->bug->report->bugsPerType->graph->xAxisName = '类型'; +$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派给'; +$lang->bug->report->bugLiveDays->graph->xAxisName = '处理时间'; +$lang->bug->report->bugHistories->graph->xAxisName = '处理步骤'; + +/* 操作记录。*/ +$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解决,方案为 $extra。', 'extra' => $lang->bug->resolutionList); +$lang->bug->action->tostory = array('main' => '$date, 由 $actor 转为需求,编号为 $extra。'); +$lang->bug->action->totask = array('main' => '$date, 由 $actor 导入为任务,编号为 $extra。'); diff --git a/module/bug/lang/zh-tw.php b/module/bug/lang/zh-tw.php index 24d04a1050..7ecb6f725f 100644 --- a/module/bug/lang/zh-tw.php +++ b/module/bug/lang/zh-tw.php @@ -1,312 +1,312 @@ - - * @package bug - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -/* 欄位列表。*/ -$lang->bug->common = '缺陷管理'; -$lang->bug->id = 'Bug編號'; -$lang->bug->product = '所屬產品'; -$lang->bug->module = '所屬模組'; -$lang->bug->path = '模組路徑'; -$lang->bug->project = '所屬項目'; -$lang->bug->story = '相關需求'; -$lang->bug->storyVersion = '需求版本'; -$lang->bug->task = '相關任務'; -$lang->bug->title = 'Bug標題'; -$lang->bug->severity = '嚴重程度'; -$lang->bug->severityAB = '級別'; -$lang->bug->pri = '優先順序'; -$lang->bug->type = 'Bug類型'; -$lang->bug->os = '操作系統'; -$lang->bug->hardware = '硬件平台'; -$lang->bug->browser = '瀏覽器'; -$lang->bug->machine = '機器硬件'; -$lang->bug->found = '如何發現'; -$lang->bug->steps = '重現步驟'; -$lang->bug->status = 'Bug狀態'; -$lang->bug->statusAB = '狀態'; -$lang->bug->activatedCount = '激活次數'; -$lang->bug->activatedCountAB = '激活次數'; -$lang->bug->confirmed = '是否確認'; -$lang->bug->toTask = '轉任務'; -$lang->bug->toStory = '轉需求'; -$lang->bug->mailto = '抄送給'; -$lang->bug->openedBy = '由誰創建'; -$lang->bug->openedByAB = '創建'; -$lang->bug->openedDate = '創建日期'; -$lang->bug->openedDateAB = '創建日期'; -$lang->bug->openedBuild = '影響版本'; -$lang->bug->assignedTo = '指派給'; -$lang->bug->assignedDate = '指派日期'; -$lang->bug->resolvedBy = '解決者'; -$lang->bug->resolvedByAB = '解決'; -$lang->bug->resolution = '解決方案'; -$lang->bug->resolutionAB = '方案'; -$lang->bug->resolvedBuild = '解決版本'; -$lang->bug->resolvedDate = '解決日期'; -$lang->bug->resolvedDateAB = '解決日期'; -$lang->bug->closedBy = '由誰關閉'; -$lang->bug->closedDate = '關閉日期'; -$lang->bug->duplicateBug = '重複Bug'; -$lang->bug->lastEditedBy = '最後修改者'; -$lang->bug->lastEditedDate = '最後修改日期'; -$lang->bug->linkBug = '相關Bug'; -$lang->bug->case = '相關用例'; -$lang->bug->files = '附件'; -$lang->bug->keywords = '關鍵詞'; -$lang->bug->lastEditedByAB = '修改者'; -$lang->bug->lastEditedDateAB = '修改日期'; - -/* 方法列表。*/ -$lang->bug->index = '首頁'; -$lang->bug->create = '創建Bug'; -$lang->bug->confirmBug = '確認'; -$lang->bug->edit = '編輯Bug'; -$lang->bug->browse = 'Bug列表'; -$lang->bug->view = 'Bug詳情'; -$lang->bug->resolve = '解決Bug'; -$lang->bug->close = '關閉Bug'; -$lang->bug->activate = '激活Bug'; -$lang->bug->reportChart = '報表統計'; -$lang->bug->export = '導出數據'; -$lang->bug->delete = '刪除Bug'; -$lang->bug->saveTemplate = '保存模板'; -$lang->bug->deleteTemplate = '刪除模板'; -$lang->bug->customFields = '自定義欄位'; -$lang->bug->restoreDefault = '恢復預設'; -$lang->bug->ajaxGetUserBugs = '介面:我的Bug'; -$lang->bug->ajaxGetModuleOwner = '介面:獲得模組的預設指派人'; -$lang->bug->confirmStoryChange = '確認需求變動'; - -/* 查詢條件列表。*/ -$lang->bug->selectProduct = '請選擇產品'; -$lang->bug->byModule = '按模組'; -$lang->bug->assignToMe = '指派給我'; -$lang->bug->openedByMe = '由我創建'; -$lang->bug->resolvedByMe = '由我解決'; -$lang->bug->closedByMe = '由我關閉'; -$lang->bug->assignToNull = '未指派'; -$lang->bug->unResolved = '未解決'; -$lang->bug->unclosed = '未關閉'; -$lang->bug->longLifeBugs = '久未處理'; -$lang->bug->postponedBugs = '被延期'; -$lang->bug->allBugs = '所有Bug'; -$lang->bug->moduleBugs = '按模組瀏覽'; -$lang->bug->byQuery = '搜索'; -$lang->bug->needConfirm = '需求變動'; -$lang->bug->allProduct = '所有產品'; - -/* 頁面標籤。*/ -$lang->bug->lblProductAndModule = '產品模組'; -$lang->bug->lblProjectAndTask = '項目任務'; -$lang->bug->lblStory = '相關需求'; -$lang->bug->lblTypeAndSeverity = '類型/嚴重程度'; -$lang->bug->lblSystemBrowserAndHardware = '系統/瀏覽器'; -$lang->bug->lblAssignedTo = '當前指派'; -$lang->bug->lblMailto = '抄送給'; -$lang->bug->lblLastEdited = '最後修改'; -$lang->bug->lblResolved = '由誰解決'; -$lang->bug->lblAllFields = '所有欄位'; -$lang->bug->lblCustomFields = '自定義欄位'; - -/* legend列表。*/ -$lang->bug->legendBasicInfo = '基本信息'; -$lang->bug->legendMailto = '抄送給'; -$lang->bug->legendAttatch = '附件'; -$lang->bug->legendLinkBugs = '相關Bug'; -$lang->bug->legendPrjStoryTask = '項目/需求/任務'; -$lang->bug->legendCases = '相關用例'; -$lang->bug->legendSteps = '重現步驟'; -$lang->bug->legendAction = '操作'; -$lang->bug->legendHistory = '歷史記錄'; -$lang->bug->legendComment = '備註'; -$lang->bug->legendLife = 'BUG的一生'; -$lang->bug->legendMisc = '其相關他'; - -/* 功能按鈕。*/ -$lang->bug->buttonConfirm = '確認'; -$lang->bug->buttonCopy = '複製'; -$lang->bug->buttonEdit = '編輯'; -$lang->bug->buttonActivate = '激活'; -$lang->bug->buttonResolve = '解決'; -$lang->bug->buttonClose = '關閉'; -$lang->bug->buttonToList = '返回'; -$lang->bug->buttonCreateTestcase = '建用例'; - -/* 交互提示。*/ -$lang->bug->confirmChangeProduct = '修改產品會導致相應的項目、需求和任務發生變化,確定嗎?'; -$lang->bug->confirmDelete = '您確認要刪除該Bug嗎?'; -$lang->bug->setTemplateTitle = '請輸入bug模板標題(保存之前請先填寫bug重現步驟):'; -$lang->bug->remindTask = '該Bug已經轉化為任務,是否更新任務(編號:%s)狀態 ?'; - -/* 模板。*/ -$lang->bug->tplStep = "

[步驟]

"; -$lang->bug->tplResult = "

[結果]

"; -$lang->bug->tplExpect = "

[期望]

"; - -/* 各個欄位取值列表。*/ -$lang->bug->severityList[3] = '3'; -$lang->bug->severityList[1] = '1'; -$lang->bug->severityList[2] = '2'; -$lang->bug->severityList[4] = '4'; - -$lang->bug->priList[0] = ''; -$lang->bug->priList[3] = '3'; -$lang->bug->priList[1] = '1'; -$lang->bug->priList[2] = '2'; -$lang->bug->priList[4] = '4'; - -$lang->bug->osList[''] = ''; -$lang->bug->osList['all'] = '全部'; -$lang->bug->osList['windows'] = 'Windows'; -$lang->bug->osList['winxp'] = 'Windows XP'; -$lang->bug->osList['win7'] = 'Windows 7'; -$lang->bug->osList['vista'] = 'Windows Vista'; -$lang->bug->osList['win2000'] = 'Windows 2000'; -$lang->bug->osList['win2003'] = 'Windows 2003'; -$lang->bug->osList['win2008'] = 'Windows 2008'; -$lang->bug->osList['winnt'] = 'Windows NT'; -$lang->bug->osList['win98'] = 'Windows 98'; -$lang->bug->osList['andriod'] = 'Andriod'; -$lang->bug->osList['ios'] = 'IOS'; -$lang->bug->osList['wp7'] = 'WP7'; -$lang->bug->osList['symbian'] = 'Symbian'; -$lang->bug->osList['linux'] = 'Linux'; -$lang->bug->osList['freebsd'] = 'FreeBSD'; -$lang->bug->osList['mac'] = 'Mac OS'; -$lang->bug->osList['unix'] = 'Unix'; -$lang->bug->osList['others'] = '其他'; - -$lang->bug->browserList[''] = ''; -$lang->bug->browserList['all'] = '全部'; -$lang->bug->browserList['ie'] = 'IE系列'; -$lang->bug->browserList['ie8'] = 'IE8'; -$lang->bug->browserList['ie9'] = 'IE9'; -$lang->bug->browserList['ie6'] = 'IE6'; -$lang->bug->browserList['ie7'] = 'IE7'; -$lang->bug->browserList['chrome'] = 'chrome'; -$lang->bug->browserList['firefox'] = 'firefox系列'; -$lang->bug->browserList['firefox2'] = 'firefox2'; -$lang->bug->browserList['firefox3'] = 'firefox3'; -$lang->bug->browserList['firefox4'] = 'firefox4'; -$lang->bug->browserList['opera'] = 'opera系列'; -$lang->bug->browserList['opera9'] = 'opera9'; -$lang->bug->browserList['oprea10'] = 'opera10'; -$lang->bug->browserList['oprea11'] = 'opera11'; -$lang->bug->browserList['safari'] = 'safari'; -$lang->bug->browserList['maxthon'] = '傲游'; -$lang->bug->browserList['uc'] = 'UC'; -$lang->bug->browserList['other'] = '其他'; - -$lang->bug->typeList[''] = ''; -$lang->bug->typeList['codeerror'] = '代碼錯誤'; -$lang->bug->typeList['interface'] = '界面優化'; -$lang->bug->typeList['designchange'] = '設計變更'; -$lang->bug->typeList['newfeature'] = '新增需求'; -$lang->bug->typeList['designdefect'] = '設計缺陷'; -$lang->bug->typeList['config'] = '配置相關'; -$lang->bug->typeList['install'] = '安裝部署'; -$lang->bug->typeList['security'] = '安全相關'; -$lang->bug->typeList['performance'] = '性能問題'; -$lang->bug->typeList['standard'] = '標準規範'; -$lang->bug->typeList['automation'] = '測試腳本'; -$lang->bug->typeList['trackthings'] = '事務跟蹤'; -$lang->bug->typeList['others'] = '其他'; - -$lang->bug->statusList[''] = ''; -$lang->bug->statusList['active'] = '激活'; -$lang->bug->statusList['resolved'] = '已解決'; -$lang->bug->statusList['closed'] = '已關閉'; - -$lang->bug->confirmedList[1] = '已確認'; -$lang->bug->confirmedList[0] = '未確認'; - -$lang->bug->resolutionList[''] = ''; -$lang->bug->resolutionList['bydesign'] = '設計如此'; -$lang->bug->resolutionList['duplicate'] = '重複Bug'; -$lang->bug->resolutionList['external'] = '外部原因'; -$lang->bug->resolutionList['fixed'] = '已解決'; -$lang->bug->resolutionList['notrepro'] = '無法重現'; -$lang->bug->resolutionList['postponed'] = '延期處理'; -$lang->bug->resolutionList['willnotfix'] = "不予解決"; -$lang->bug->resolutionList['tostory'] = '轉為需求'; - -/* 統計報表。*/ -$lang->bug->report->common = '統計報表'; -$lang->bug->report->select = '請選擇報表類型'; -$lang->bug->report->create = '生成報表'; -$lang->bug->report->selectAll = '全選'; -$lang->bug->report->selectReverse = '反選'; - -$lang->bug->report->charts['bugsPerProject'] = '項目Bug數量'; -$lang->bug->report->charts['bugsPerModule'] = '模組Bug數量'; -$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug數'; -$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解決Bug數'; -$lang->bug->report->charts['closedBugsPerDay'] = '每天關閉的Bug數'; -$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug數'; -$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解決的Bug數'; -$lang->bug->report->charts['closedBugsPerUser'] = '每人關閉的Bug數'; -$lang->bug->report->charts['bugsPerSeverity'] = 'Bug嚴重程度統計'; -$lang->bug->report->charts['bugsPerResolution'] = 'Bug解決方案統計'; -$lang->bug->report->charts['bugsPerStatus'] = 'Bug狀態統計'; -$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次數統計'; -$lang->bug->report->charts['bugsPerType'] = 'Bug類型統計'; -$lang->bug->report->charts['bugsPerAssignedTo'] = '指派給統計'; -//$lang->bug->report->charts['bugLiveDays'] = 'Bug處理時間統計'; -//$lang->bug->report->charts['bugHistories'] = 'Bug處理步驟統計'; - -$lang->bug->report->options->swf = 'pie2d'; -$lang->bug->report->options->width = 'auto'; -$lang->bug->report->options->height = 300; -$lang->bug->report->options->graph->baseFontSize = 12; -$lang->bug->report->options->graph->showNames = 1; -$lang->bug->report->options->graph->formatNumber = 1; -$lang->bug->report->options->graph->decimalPrecision = 0; -$lang->bug->report->options->graph->animation = 0; -$lang->bug->report->options->graph->rotateNames = 0; -$lang->bug->report->options->graph->yAxisName = 'COUNT'; -$lang->bug->report->options->graph->pieRadius = 100; // 餅圖直徑。 -$lang->bug->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 - -$lang->bug->report->bugsPerProject->graph->xAxisName = '項目'; -$lang->bug->report->bugsPerModule->graph->xAxisName = '模組'; - -$lang->bug->report->openedBugsPerDay->swf = 'column2d'; -$lang->bug->report->openedBugsPerDay->height = 400; -$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; -$lang->bug->report->resolvedBugsPerDay->height = 400; -$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->closedBugsPerDay->swf = 'column2d'; -$lang->bug->report->closedBugsPerDay->height = 400; -$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期'; -$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; - -$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用戶'; -$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用戶'; -$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用戶'; - -$lang->bug->report->bugsPerSeverity->graph->xAxisName = '嚴重程度'; -$lang->bug->report->bugsPerResolution->graph->xAxisName = '解決方案'; -$lang->bug->report->bugsPerStatus->graph->xAxisName = '狀態'; -$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次數'; -$lang->bug->report->bugsPerType->graph->xAxisName = '類型'; -$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派給'; -$lang->bug->report->bugLiveDays->graph->xAxisName = '處理時間'; -$lang->bug->report->bugHistories->graph->xAxisName = '處理步驟'; - -/* 操作記錄。*/ -$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解決,方案為 $extra。', 'extra' => $lang->bug->resolutionList); -$lang->bug->action->tostory = array('main' => '$date, 由 $actor 轉為需求,編號為 $extra。'); -$lang->bug->action->totask = array('main' => '$date, 由 $actor 導入為任務,編號為 $extra。'); + + * @package bug + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +/* 欄位列表。*/ +$lang->bug->common = '缺陷管理'; +$lang->bug->id = 'Bug編號'; +$lang->bug->product = '所屬產品'; +$lang->bug->module = '所屬模組'; +$lang->bug->path = '模組路徑'; +$lang->bug->project = '所屬項目'; +$lang->bug->story = '相關需求'; +$lang->bug->storyVersion = '需求版本'; +$lang->bug->task = '相關任務'; +$lang->bug->title = 'Bug標題'; +$lang->bug->severity = '嚴重程度'; +$lang->bug->severityAB = '級別'; +$lang->bug->pri = '優先順序'; +$lang->bug->type = 'Bug類型'; +$lang->bug->os = '操作系統'; +$lang->bug->hardware = '硬件平台'; +$lang->bug->browser = '瀏覽器'; +$lang->bug->machine = '機器硬件'; +$lang->bug->found = '如何發現'; +$lang->bug->steps = '重現步驟'; +$lang->bug->status = 'Bug狀態'; +$lang->bug->statusAB = '狀態'; +$lang->bug->activatedCount = '激活次數'; +$lang->bug->activatedCountAB = '激活次數'; +$lang->bug->confirmed = '是否確認'; +$lang->bug->toTask = '轉任務'; +$lang->bug->toStory = '轉需求'; +$lang->bug->mailto = '抄送給'; +$lang->bug->openedBy = '由誰創建'; +$lang->bug->openedByAB = '創建'; +$lang->bug->openedDate = '創建日期'; +$lang->bug->openedDateAB = '創建日期'; +$lang->bug->openedBuild = '影響版本'; +$lang->bug->assignedTo = '指派給'; +$lang->bug->assignedDate = '指派日期'; +$lang->bug->resolvedBy = '解決者'; +$lang->bug->resolvedByAB = '解決'; +$lang->bug->resolution = '解決方案'; +$lang->bug->resolutionAB = '方案'; +$lang->bug->resolvedBuild = '解決版本'; +$lang->bug->resolvedDate = '解決日期'; +$lang->bug->resolvedDateAB = '解決日期'; +$lang->bug->closedBy = '由誰關閉'; +$lang->bug->closedDate = '關閉日期'; +$lang->bug->duplicateBug = '重複Bug'; +$lang->bug->lastEditedBy = '最後修改者'; +$lang->bug->lastEditedDate = '最後修改日期'; +$lang->bug->linkBug = '相關Bug'; +$lang->bug->case = '相關用例'; +$lang->bug->files = '附件'; +$lang->bug->keywords = '關鍵詞'; +$lang->bug->lastEditedByAB = '修改者'; +$lang->bug->lastEditedDateAB = '修改日期'; + +/* 方法列表。*/ +$lang->bug->index = '首頁'; +$lang->bug->create = '創建Bug'; +$lang->bug->confirmBug = '確認'; +$lang->bug->edit = '編輯Bug'; +$lang->bug->browse = 'Bug列表'; +$lang->bug->view = 'Bug詳情'; +$lang->bug->resolve = '解決Bug'; +$lang->bug->close = '關閉Bug'; +$lang->bug->activate = '激活Bug'; +$lang->bug->reportChart = '報表統計'; +$lang->bug->export = '導出數據'; +$lang->bug->delete = '刪除Bug'; +$lang->bug->saveTemplate = '保存模板'; +$lang->bug->deleteTemplate = '刪除模板'; +$lang->bug->customFields = '自定義欄位'; +$lang->bug->restoreDefault = '恢復預設'; +$lang->bug->ajaxGetUserBugs = '介面:我的Bug'; +$lang->bug->ajaxGetModuleOwner = '介面:獲得模組的預設指派人'; +$lang->bug->confirmStoryChange = '確認需求變動'; + +/* 查詢條件列表。*/ +$lang->bug->selectProduct = '請選擇產品'; +$lang->bug->byModule = '按模組'; +$lang->bug->assignToMe = '指派給我'; +$lang->bug->openedByMe = '由我創建'; +$lang->bug->resolvedByMe = '由我解決'; +$lang->bug->closedByMe = '由我關閉'; +$lang->bug->assignToNull = '未指派'; +$lang->bug->unResolved = '未解決'; +$lang->bug->unclosed = '未關閉'; +$lang->bug->longLifeBugs = '久未處理'; +$lang->bug->postponedBugs = '被延期'; +$lang->bug->allBugs = '所有Bug'; +$lang->bug->moduleBugs = '按模組瀏覽'; +$lang->bug->byQuery = '搜索'; +$lang->bug->needConfirm = '需求變動'; +$lang->bug->allProduct = '所有產品'; + +/* 頁面標籤。*/ +$lang->bug->lblProductAndModule = '產品模組'; +$lang->bug->lblProjectAndTask = '項目任務'; +$lang->bug->lblStory = '相關需求'; +$lang->bug->lblTypeAndSeverity = '類型/嚴重程度'; +$lang->bug->lblSystemBrowserAndHardware = '系統/瀏覽器'; +$lang->bug->lblAssignedTo = '當前指派'; +$lang->bug->lblMailto = '抄送給'; +$lang->bug->lblLastEdited = '最後修改'; +$lang->bug->lblResolved = '由誰解決'; +$lang->bug->lblAllFields = '所有欄位'; +$lang->bug->lblCustomFields = '自定義欄位'; + +/* legend列表。*/ +$lang->bug->legendBasicInfo = '基本信息'; +$lang->bug->legendMailto = '抄送給'; +$lang->bug->legendAttatch = '附件'; +$lang->bug->legendLinkBugs = '相關Bug'; +$lang->bug->legendPrjStoryTask = '項目/需求/任務'; +$lang->bug->legendCases = '相關用例'; +$lang->bug->legendSteps = '重現步驟'; +$lang->bug->legendAction = '操作'; +$lang->bug->legendHistory = '歷史記錄'; +$lang->bug->legendComment = '備註'; +$lang->bug->legendLife = 'BUG的一生'; +$lang->bug->legendMisc = '其相關他'; + +/* 功能按鈕。*/ +$lang->bug->buttonConfirm = '確認'; +$lang->bug->buttonCopy = '複製'; +$lang->bug->buttonEdit = '編輯'; +$lang->bug->buttonActivate = '激活'; +$lang->bug->buttonResolve = '解決'; +$lang->bug->buttonClose = '關閉'; +$lang->bug->buttonToList = '返回'; +$lang->bug->buttonCreateTestcase = '建用例'; + +/* 交互提示。*/ +$lang->bug->confirmChangeProduct = '修改產品會導致相應的項目、需求和任務發生變化,確定嗎?'; +$lang->bug->confirmDelete = '您確認要刪除該Bug嗎?'; +$lang->bug->setTemplateTitle = '請輸入bug模板標題(保存之前請先填寫bug重現步驟):'; +$lang->bug->remindTask = '該Bug已經轉化為任務,是否更新任務(編號:%s)狀態 ?'; + +/* 模板。*/ +$lang->bug->tplStep = "

[步驟]

"; +$lang->bug->tplResult = "

[結果]

"; +$lang->bug->tplExpect = "

[期望]

"; + +/* 各個欄位取值列表。*/ +$lang->bug->severityList[3] = '3'; +$lang->bug->severityList[1] = '1'; +$lang->bug->severityList[2] = '2'; +$lang->bug->severityList[4] = '4'; + +$lang->bug->priList[0] = ''; +$lang->bug->priList[3] = '3'; +$lang->bug->priList[1] = '1'; +$lang->bug->priList[2] = '2'; +$lang->bug->priList[4] = '4'; + +$lang->bug->osList[''] = ''; +$lang->bug->osList['all'] = '全部'; +$lang->bug->osList['windows'] = 'Windows'; +$lang->bug->osList['winxp'] = 'Windows XP'; +$lang->bug->osList['win7'] = 'Windows 7'; +$lang->bug->osList['vista'] = 'Windows Vista'; +$lang->bug->osList['win2000'] = 'Windows 2000'; +$lang->bug->osList['win2003'] = 'Windows 2003'; +$lang->bug->osList['win2008'] = 'Windows 2008'; +$lang->bug->osList['winnt'] = 'Windows NT'; +$lang->bug->osList['win98'] = 'Windows 98'; +$lang->bug->osList['andriod'] = 'Andriod'; +$lang->bug->osList['ios'] = 'IOS'; +$lang->bug->osList['wp7'] = 'WP7'; +$lang->bug->osList['symbian'] = 'Symbian'; +$lang->bug->osList['linux'] = 'Linux'; +$lang->bug->osList['freebsd'] = 'FreeBSD'; +$lang->bug->osList['mac'] = 'Mac OS'; +$lang->bug->osList['unix'] = 'Unix'; +$lang->bug->osList['others'] = '其他'; + +$lang->bug->browserList[''] = ''; +$lang->bug->browserList['all'] = '全部'; +$lang->bug->browserList['ie'] = 'IE系列'; +$lang->bug->browserList['ie8'] = 'IE8'; +$lang->bug->browserList['ie9'] = 'IE9'; +$lang->bug->browserList['ie6'] = 'IE6'; +$lang->bug->browserList['ie7'] = 'IE7'; +$lang->bug->browserList['chrome'] = 'chrome'; +$lang->bug->browserList['firefox'] = 'firefox系列'; +$lang->bug->browserList['firefox2'] = 'firefox2'; +$lang->bug->browserList['firefox3'] = 'firefox3'; +$lang->bug->browserList['firefox4'] = 'firefox4'; +$lang->bug->browserList['opera'] = 'opera系列'; +$lang->bug->browserList['opera9'] = 'opera9'; +$lang->bug->browserList['oprea10'] = 'opera10'; +$lang->bug->browserList['oprea11'] = 'opera11'; +$lang->bug->browserList['safari'] = 'safari'; +$lang->bug->browserList['maxthon'] = '傲游'; +$lang->bug->browserList['uc'] = 'UC'; +$lang->bug->browserList['other'] = '其他'; + +$lang->bug->typeList[''] = ''; +$lang->bug->typeList['codeerror'] = '代碼錯誤'; +$lang->bug->typeList['interface'] = '界面優化'; +$lang->bug->typeList['designchange'] = '設計變更'; +$lang->bug->typeList['newfeature'] = '新增需求'; +$lang->bug->typeList['designdefect'] = '設計缺陷'; +$lang->bug->typeList['config'] = '配置相關'; +$lang->bug->typeList['install'] = '安裝部署'; +$lang->bug->typeList['security'] = '安全相關'; +$lang->bug->typeList['performance'] = '性能問題'; +$lang->bug->typeList['standard'] = '標準規範'; +$lang->bug->typeList['automation'] = '測試腳本'; +$lang->bug->typeList['trackthings'] = '事務跟蹤'; +$lang->bug->typeList['others'] = '其他'; + +$lang->bug->statusList[''] = ''; +$lang->bug->statusList['active'] = '激活'; +$lang->bug->statusList['resolved'] = '已解決'; +$lang->bug->statusList['closed'] = '已關閉'; + +$lang->bug->confirmedList[1] = '已確認'; +$lang->bug->confirmedList[0] = '未確認'; + +$lang->bug->resolutionList[''] = ''; +$lang->bug->resolutionList['bydesign'] = '設計如此'; +$lang->bug->resolutionList['duplicate'] = '重複Bug'; +$lang->bug->resolutionList['external'] = '外部原因'; +$lang->bug->resolutionList['fixed'] = '已解決'; +$lang->bug->resolutionList['notrepro'] = '無法重現'; +$lang->bug->resolutionList['postponed'] = '延期處理'; +$lang->bug->resolutionList['willnotfix'] = "不予解決"; +$lang->bug->resolutionList['tostory'] = '轉為需求'; + +/* 統計報表。*/ +$lang->bug->report->common = '統計報表'; +$lang->bug->report->select = '請選擇報表類型'; +$lang->bug->report->create = '生成報表'; +$lang->bug->report->selectAll = '全選'; +$lang->bug->report->selectReverse = '反選'; + +$lang->bug->report->charts['bugsPerProject'] = '項目Bug數量'; +$lang->bug->report->charts['bugsPerModule'] = '模組Bug數量'; +$lang->bug->report->charts['openedBugsPerDay'] = '每天新增Bug數'; +$lang->bug->report->charts['resolvedBugsPerDay'] = '每天解決Bug數'; +$lang->bug->report->charts['closedBugsPerDay'] = '每天關閉的Bug數'; +$lang->bug->report->charts['openedBugsPerUser'] = '每人提交的Bug數'; +$lang->bug->report->charts['resolvedBugsPerUser'] = '每人解決的Bug數'; +$lang->bug->report->charts['closedBugsPerUser'] = '每人關閉的Bug數'; +$lang->bug->report->charts['bugsPerSeverity'] = 'Bug嚴重程度統計'; +$lang->bug->report->charts['bugsPerResolution'] = 'Bug解決方案統計'; +$lang->bug->report->charts['bugsPerStatus'] = 'Bug狀態統計'; +$lang->bug->report->charts['bugsPerActivatedCount'] = 'Bug激活次數統計'; +$lang->bug->report->charts['bugsPerType'] = 'Bug類型統計'; +$lang->bug->report->charts['bugsPerAssignedTo'] = '指派給統計'; +//$lang->bug->report->charts['bugLiveDays'] = 'Bug處理時間統計'; +//$lang->bug->report->charts['bugHistories'] = 'Bug處理步驟統計'; + +$lang->bug->report->options->swf = 'pie2d'; +$lang->bug->report->options->width = 'auto'; +$lang->bug->report->options->height = 300; +$lang->bug->report->options->graph->baseFontSize = 12; +$lang->bug->report->options->graph->showNames = 1; +$lang->bug->report->options->graph->formatNumber = 1; +$lang->bug->report->options->graph->decimalPrecision = 0; +$lang->bug->report->options->graph->animation = 0; +$lang->bug->report->options->graph->rotateNames = 0; +$lang->bug->report->options->graph->yAxisName = 'COUNT'; +$lang->bug->report->options->graph->pieRadius = 100; // 餅圖直徑。 +$lang->bug->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 + +$lang->bug->report->bugsPerProject->graph->xAxisName = '項目'; +$lang->bug->report->bugsPerModule->graph->xAxisName = '模組'; + +$lang->bug->report->openedBugsPerDay->swf = 'column2d'; +$lang->bug->report->openedBugsPerDay->height = 400; +$lang->bug->report->openedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->openedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->resolvedBugsPerDay->swf = 'column2d'; +$lang->bug->report->resolvedBugsPerDay->height = 400; +$lang->bug->report->resolvedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->resolvedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->closedBugsPerDay->swf = 'column2d'; +$lang->bug->report->closedBugsPerDay->height = 400; +$lang->bug->report->closedBugsPerDay->graph->xAxisName = '日期'; +$lang->bug->report->closedBugsPerDay->graph->rotateNames = 1; + +$lang->bug->report->openedBugsPerUser->graph->xAxisName = '用戶'; +$lang->bug->report->resolvedBugsPerUser->graph->xAxisName= '用戶'; +$lang->bug->report->closedBugsPerUser->graph->xAxisName = '用戶'; + +$lang->bug->report->bugsPerSeverity->graph->xAxisName = '嚴重程度'; +$lang->bug->report->bugsPerResolution->graph->xAxisName = '解決方案'; +$lang->bug->report->bugsPerStatus->graph->xAxisName = '狀態'; +$lang->bug->report->bugsPerActivatedCount->graph->xAxisName = '激活次數'; +$lang->bug->report->bugsPerType->graph->xAxisName = '類型'; +$lang->bug->report->bugsPerAssignedTo->graph->xAxisName = '指派給'; +$lang->bug->report->bugLiveDays->graph->xAxisName = '處理時間'; +$lang->bug->report->bugHistories->graph->xAxisName = '處理步驟'; + +/* 操作記錄。*/ +$lang->bug->action->resolved = array('main' => '$date, 由 $actor 解決,方案為 $extra。', 'extra' => $lang->bug->resolutionList); +$lang->bug->action->tostory = array('main' => '$date, 由 $actor 轉為需求,編號為 $extra。'); +$lang->bug->action->totask = array('main' => '$date, 由 $actor 導入為任務,編號為 $extra。'); diff --git a/module/bug/model.php b/module/bug/model.php index d15a3ca542..a0624d30fd 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -1,988 +1,988 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> -loadModel('product')->setMenu($products, $productID); - $selectHtml = $this->product->select($products, $productID, 'bug', 'browse'); - foreach($this->lang->bug->menu as $key => $menu) - { - $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID; - common::setMenuVars($this->lang->bug->menu, $key, $replace); - } - } - - /** - * Create a bug. - * - * @access public - * @return int|bool - */ - public function create() - { - $now = helper::now(); - $bug = fixer::input('post') - ->add('openedBy', $this->app->user->account) - ->add('openedDate', $now) - ->setDefault('project,story,task', 0) - ->setDefault('openedBuild', '') - ->setIF($this->post->assignedTo != '', 'assignedDate', $now) - ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->specialChars('title,keyword') - ->cleanInt('product, module, severity') - ->join('openedBuild', ',') - ->remove('files, labels') - ->get(); - $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec(); - if(!dao::isError()) - { - $bugID = $this->dao->lastInsertID(); - $this->loadModel('file')->saveUpload('bug', $bugID); - return $bugID; - } - return false; - } - - /** - * Get bugs of a module. - * - * @param int $productID - * @param string|array $moduleIds - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getModuleBugs($productID, $moduleIds = 0, $projects, $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('*')->from(TABLE_BUG) - ->where('product')->eq((int)$productID) - ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi() - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get info of a bug. - * - * @param int $bugID - * @access public - * @return object - */ - public function getById($bugID) - { - $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName') - ->from(TABLE_BUG)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') - ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id') - ->where('t1.id')->eq((int)$bugID)->fetch(); - if(!$bug) return false; - $bug->steps = $this->loadModel('file')->setImgSize($bug->steps); - foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = ''; - if($bug->mailto) - { - $bug->mailto = ltrim(trim($bug->mailto), ','); // Remove the first , - $bug->mailto = str_replace(' ', '', $bug->mailto); - $bug->mailto = rtrim($bug->mailto, ',') . ','; - $bug->mailto = str_replace(',', ', ', $bug->mailto); - } - if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title'); - if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title'); - if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs(); - if($bug->toStory > 0) $bug->toStoryTitle = $this->dao->findById($bug->toStory)->from(TABLE_STORY)->fields('title')->fetch('title'); - if($bug->toTask > 0) $bug->toTaskTitle = $this->dao->findById($bug->toTask)->from(TABLE_TASK)->fields('name')->fetch('name'); - $bug->files = $this->loadModel('file')->getByObject('bug', $bugID); - return $bug; - } - - /** - * getActiveBugs - * - * @param object $pager - * @param int $projectID - * @access public - * @return array - */ - public function getActiveBugs($pager, $projectID, $products) - { - return $this->dao->select('*')->from(TABLE_BUG) - ->where('status')->eq('active') - ->andWhere('toTask')->eq(0) - ->andWhere('tostory')->eq(0) - ->beginIF(!empty($products))->andWhere('product')->in($products)->fi() - ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy('id desc') - ->page($pager) - ->fetchAll(); - } - - /** - * Update a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function update($bugID) - { - $oldBug = $this->getById($bugID); - $now = helper::now(); - $bug = fixer::input('post') - ->cleanInt('product,module,severity,project,story,task') - ->specialChars('title,keyword') - ->remove('comment,files,labels') - ->setDefault('project,module,project,story,task,duplicateBug', 0) - ->setDefault('openedBuild', '') - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->join('openedBuild', ',') - ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) - ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) - ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) - ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) - ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) - ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') - ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) - ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) - ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') - ->setIF($this->post->resolution != '', 'confirmed', 1) - ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->get(); - - $this->dao->update(TABLE_BUG)->data($bug) - ->autoCheck() - ->batchCheck($this->config->bug->edit->requiredFields, 'notempty') - ->checkIF($bug->resolvedBy, 'resolution', 'notempty') - ->checkIF($bug->closedBy, 'resolution', 'notempty') - ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') - ->where('id')->eq((int)$bugID) - ->exec(); - if(!dao::isError()) return common::createChanges($oldBug, $bug); - } - - /** - * Confirm a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function confirm($bugID) - { - $now = helper::now(); - $bug->confirmed = 1; - $bug->lastEditedBy = $this->app->user->account; - $bug->lastEditedDate = $now; - $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec(); - } - - /** - * Resolve a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function resolve($bugID) - { - $now = helper::now(); - $bug = fixer::input('post') - ->add('resolvedBy', $this->app->user->account) - ->add('resolvedDate', $now) - ->add('status', 'resolved') - ->add('confirmed', 1) - ->add('assignedDate', $now) - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->setDefault('duplicateBug', 0) - ->setDefault('assignedTo', $oldBug->openedBy) - ->remove('comment') - ->get(); - - $this->dao->update(TABLE_BUG)->data($bug) - ->autoCheck() - ->batchCheck($this->config->bug->resolve->requiredFields, 'notempty') - ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') - ->checkIF($bug->resolution == 'fixed', 'resolvedBuild','notempty') - ->where('id')->eq((int)$bugID) - ->exec(); - } - - /** - * Activate a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function activate($bugID) - { - $oldBug = $this->getById($bugID); - $now = helper::now(); - $bug = fixer::input('post') - ->setDefault('assignedTo', $oldBug->resolvedBy) - ->add('assignedDate', $now) - ->add('resolution', '') - ->add('status', 'active') - ->add('resolvedDate', '0000-00-00') - ->add('resolvedBy', '') - ->add('resolvedBuild', '') - ->add('closedBy', '') - ->add('closedDate', '0000-00-00') - ->add('duplicateBug', 0) - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->join('openedBuild', ',') - ->remove('comment,files,labels') - ->get(); - - $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); - $this->dao->update(TABLE_BUG)->set('activatedCount = activatedCount + 1')->where('id')->eq((int)$bugID)->exec(); - } - - /** - * Close a bug. - * - * @param int $bugID - * @access public - * @return void - */ - public function close($bugID) - { - $oldBug = $this->getById($bugID); - $now = helper::now(); - $bug = fixer::input('post') - ->add('assignedTo', 'closed') - ->add('assignedDate', $now) - ->add('status', 'closed') - ->add('closedBy', $this->app->user->account) - ->add('closedDate', $now) - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->add('confirmed', 1) - ->remove('comment') - ->get(); - - $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); - } - - /** - * Extract accounts from some bugs. - * - * @param int $bugs - * @access public - * @return array - */ - public function extractAccountsFromList($bugs) - { - $accounts = array(); - foreach($bugs as $bug) - { - if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; - if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; - if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; - if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; - if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; - } - return array_unique($accounts); - } - - /** - * Extract accounts from a bug. - * - * @param object $bug - * @access public - * @return array - */ - public function extractAccountsFromSingle($bug) - { - $accounts = array(); - if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; - if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; - if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; - if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; - if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; - return array_unique($accounts); - } - - /** - * Get bug pairs of a user. - * - * @param int $account - * @param bool $appendProduct - * @param int $limit - * @access public - * @return array - */ - public function getUserBugPairs($account, $appendProduct = true, $limit = 0) - { - $bugs = array(); - $stmt = $this->dao->select('t1.id, t1.title, t2.name as product') - ->from(TABLE_BUG)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product=t2.id') - ->where('t1.assignedTo')->eq($account) - ->andWhere('t1.deleted')->eq(0) - ->orderBy('id desc') - ->beginIF($limit > 0)->limit($limit)->fi() - ->query(); - while($bug = $stmt->fetch()) - { - if($appendProduct) $bug->title = $bug->product . ' / ' . $bug->title; - $bugs[$bug->id] = $bug->title; - } - return $bugs; - } - - /** - * Get bugs of a project. - * - * @param int $projectID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null, $build = 0) - { - return $this->dao->select('*')->from(TABLE_BUG) - ->where('project')->eq((int)$projectID) - ->beginIF($build != 0)->andWhere('openedBuild')->eq($build)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bug info from a result. - * - * @param int $resultID - * @param int $caseID - * @param int $version - * @access public - * @return array - */ - public function getBugInfoFromResult($resultID, $caseID = 0, $version = 0) - { - $title = ''; - $bugSteps = ''; - - $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch(); - if($caseID > 0) - $run->case = $this->loadModel('testcase')->getById($caseID, $result->version); - else - $run = $this->loadModel('testtask')->getRunById($result->run); - if($result and $result->caseResult == 'fail') - { - $title = $run->case->title; - $caseSteps = $run->case->steps; - $stepResults = unserialize($result->stepResults); - if($run->case->precondition != '') - { - $bugSteps = "

[" . $this->lang->testcase->precondition . "]

" . "\n" . $run->case->precondition; - } - $bugSteps .= $this->lang->bug->tplStep; - if(!empty($stepResults)) - { - foreach($caseSteps as $key => $step) - { - $bugSteps .= ($key + 1) . '. ' .$step->desc . "
"; - if($stepResults[$step->id]['result'] == 'fail') - { - $bugSteps .= $this->lang->bug->tplResult; - $bugSteps .= $stepResults[$step->id]['real'] . "
"; - $bugSteps .= $this->lang->bug->tplExpect; - $bugSteps .= $step->expect; - break; - } - } - } - else - { - $bugSteps .= $this->lang->bug->tplResult; - $bugSteps .= $this->lang->bug->tplExpect; - } - } - return array('title' => $title, 'steps' => $bugSteps, 'storyID' => $run->case->story); - } - - /** - * Get report data of bugs per project - * - * @access public - * @return array - */ - public function getDataOfBugsPerProject() - { - $datas = $this->dao->select('project as name, count(project) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('project')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $projects = $this->loadModel('project')->getPairs(); - foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of bugs per module - * - * @access public - * @return array - */ - public function getDataOfBugsPerModule() - { - $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('module')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs(); - foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/'; - return $datas; - } - - /** - * Get report data of opened bugs per day. - * - * @access public - * @return array - */ - public function getDataOfOpenedBugsPerDay() - { - return $this->dao->select('DATE_FORMAT(openedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('openedDate')->fetchAll(); - } - - /** - * Get report data of resolved bugs per day. - * - * @access public - * @return array - */ - public function getDataOfResolvedBugsPerDay() - { - return $this->dao->select('DATE_FORMAT(resolvedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) - ->where($this->session->bugReportCondition)->groupBy('name') - ->having('name != 0000-00-00') - ->orderBy('resolvedDate') - ->fetchAll(); - } - - /** - * Get report data of closed bugs per day. - * - * @access public - * @return array - */ - public function getDataOfClosedBugsPerDay() - { - return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) - ->where($this->session->bugReportCondition)->groupBy('name') - ->having('name != 0000-00-00') - ->orderBy('closedDate')->fetchAll(); - } - - /** - * Get report data of openeded bugs per user. - * - * @access public - * @return array - */ - public function getDataOfOpenedBugsPerUser() - { - $datas = $this->dao->select('openedBy AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - return $datas; - } - - /** - * Get report data of resolved bugs per user. - * - * @access public - * @return array - */ - public function getDataOfResolvedBugsPerUser() - { - $datas = $this->dao->select('resolvedBy AS name, COUNT(*) AS value') - ->from(TABLE_BUG)->where($this->session->bugReportCondition) - ->andWhere('resolvedBy')->ne('') - ->groupBy('name') - ->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - return $datas; - } - - /** - * Get report data of closed bugs per user. - * - * @access public - * @return array - */ - public function getDataOfClosedBugsPerUser() - { - $datas = $this->dao->select('closedBy AS name, COUNT(*) AS value') - ->from(TABLE_BUG) - ->where($this->session->bugReportCondition) - ->andWhere('closedBy')->ne('') - ->groupBy('name') - ->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - return $datas; - } - - /** - * Get report data of bugs per severity. - * - * @access public - * @return array - */ - public function getDataOfBugsPerSeverity() - { - $datas = $this->dao->select('severity AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $severity => $data) if(isset($this->lang->bug->severityList[$severity])) $data->name = $this->lang->bug->severityList[$severity]; - return $datas; - } - - /** - * Get report data of bugs per resolution. - * - * @access public - * @return array - */ - public function getDataOfBugsPerResolution() - { - $datas = $this->dao->select('resolution AS name, COUNT(*) AS value') - ->from(TABLE_BUG) - ->where($this->session->bugReportCondition) - ->andWhere('resolution')->ne('') - ->groupBy('name')->orderBy('value DESC') - ->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $resolution => $data) if(isset($this->lang->bug->resolutionList[$resolution])) $data->name = $this->lang->bug->resolutionList[$resolution]; - return $datas; - } - - /** - * Get report data of bugs per status. - * - * @access public - * @return array - */ - public function getDataOfBugsPerStatus() - { - $datas = $this->dao->select('status AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $status => $data) if(isset($this->lang->bug->statusList[$status])) $data->name = $this->lang->bug->statusList[$status]; - return $datas; - } - - /** - * Get report data of bugs per status. - * - * @access public - * @return array - */ - public function getDataOfBugsPerActivatedCount() - { - $datas = $this->dao->select('activatedCount AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $data) $data->name = $this->lang->bug->report->bugsPerActivatedCount->graph->xAxisName . ':' . $data->name; - return $datas; - } - - /** - * Get report data of bugs per type. - * - * @access public - * @return array - */ - public function getDataOfBugsPerType() - { - $datas = $this->dao->select('type AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $type => $data) if(isset($this->lang->bug->typeList[$type])) $data->name = $this->lang->bug->typeList[$type]; - return $datas; - } - - /** - * getDataOfBugsPerAssignedTo - * - * @access public - * @return void - */ - public function getDataOfBugsPerAssignedTo() - { - $datas = $this->dao->select('assignedTo AS name, COUNT(*) AS value') - ->from(TABLE_BUG)->where($this->session->bugReportCondition) - ->groupBy('name') - ->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - return $datas; - } - - /** - * Merge the default chart settings and the settings of current chart. - * - * @param string $chartType - * @access public - * @return void - */ - public function mergeChartOption($chartType) - { - $chartOption = $this->lang->bug->report->$chartType; - $commonOption = $this->lang->bug->report->options; - - $chartOption->graph->caption = $this->lang->bug->report->charts[$chartType]; - if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; - if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; - if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; - - /* 合并配置。*/ - foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; - } - - /** - * Get bug templates of a user. - * - * @param string $account - * @access public - * @return array - */ - public function getUserBugTemplates($account) - { - $templates = $this->dao->select('id, title, content') - ->from(TABLE_USERTPL) - ->where('account')->eq($account) - ->orderBy('id') - ->fetchAll(); - return $templates; - } - - /** - * Save user template. - * - * @access public - * @return void - */ - public function saveUserBugTemplate() - { - $template = fixer::input('post') - ->specialChars('title') - ->add('account', $this->app->user->account) - ->add('type', 'bug') - ->get(); - $this->dao->insert(TABLE_USERTPL)->data($template)->autoCheck('title, content', 'notempty')->check('title', 'unique')->exec(); - } - - /** - * Return the file => label pairs of some fields. - * - * @param string $fields - * @access public - * @return array - */ - public function getFieldPairs($fields) - { - $fields = explode(',', $fields); - foreach($fields as $key => $field) - { - $field = trim($field); - $fields[$field] = $this->lang->bug->$field; - unset($fields[$key]); - } - return $fields; - } - - /** - * Get all bugs. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getAllBugs($productID, $projects, $orderBy, $pager) - { - return $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs of assign to me. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByAssigntome($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs of opened by me. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByOpenedbyme($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs of resolved by me. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByResolvedbyme($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs of nobody to do. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByAssigntonull($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs the status is active or unclosed. - * - * @param int $productID - * @param array $projects - * @param string $status - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByStatus($productID, $projects, $status, $orderBy, $pager) - { - return $this->dao->select('*')->from(TABLE_BUG) - ->where('project')->in(array_keys($projects)) - ->andWhere('product')->eq($productID) - ->beginIF($status == 'unclosed')->andWhere('status')->ne('closed')->fi() - ->beginIF($status == 'unresolved')->andWhere('status')->eq('active')->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get unresolve bugs for long time. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByLonglifebugs($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->andWhere('openedDate')->lt(date(DT_DATE1,strtotime('-7 days'))) - ->andWhere('deleted')->eq(0) - ->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get postponed bugs. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByPostponedbugs($productID, $projects, $orderBy, $pager) - { - return $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID) - ->andWhere('project')->in(array_keys($projects)) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get bugs need confirm. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByNeedconfirm($productID, $projects, $orderBy, $pager) - { - return $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_BUG)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') - ->where("t2.status = 'active'") - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t2.version > t1.storyVersion') - ->andWhere('t1.project')->in(array_keys($projects)) - ->orderBy($orderBy) - ->fetchAll(); - } - - /** - * Get bugs by search. - * - * @param int $productID - * @param array $projects - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getBySearch($productID, $projects, $queryID, $orderBy, $pager) - { - if($queryID) - { - $query = $this->loadModel('search')->getQuery($queryID); - if($query) - { - $this->session->set('bugQuery', $query->sql); - $this->session->set('bugForm', $query->form); - } - else - { - $this->session->set('bugQuery', ' 1 = 1'); - } - } - else - { - if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); - } - - /* check the purview of projects.*/ - if(strpos($this->session->bugQuery, '`project`') === false) - { - $var = $this->session->bugQuery . 'AND `project`' . helper::dbIN(array_keys($projects)); - $this->session->set('bugQuery', "$var"); - } - - $bugQuery = str_replace("`product` = 'all'", '1', $this->session->bugQuery); // Search all product. - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - return $bugs; - } - - /** - * Form customed bugs. - * - * @param array $bugs - * @access public - * @return array - */ - public function formCustomedBugs($bugs) - { - /* Get related objects id lists. */ - $relatedModuleIdList = array(); - $relatedStoryIdList = array(); - $relatedTaskIdList = array(); - $relatedCaseIdList = array(); - $relatedProjectIdList = array(); - - foreach($bugs as $bug) - { - $relatedModuleIdList[$bug->module] = $bug->module; - $relatedStoryIdList[$bug->story] = $bug->story; - $relatedTaskIdList[$bug->task] = $bug->task; - $relatedCaseIdList[$bug->case] = $bug->case; - $relatedProjectIdList[$bug->project] = $bug->project; - - /* Get related objects title or names. */ - $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); - $relatedStories = $this->dao->select('id, title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs(); - $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); - $relatedProjects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->in($relatedProjectIdList)->fetchPairs(); - - /* fill some field with useful value. */ - if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module]; - if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story]; - if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task]; - if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case]; - if(isset($relatedProjects[$bug->project])) $bug->project = $relatedProjects[$bug->project]; - } - return $bugs; - } -} + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> +loadModel('product')->setMenu($products, $productID); + $selectHtml = $this->product->select($products, $productID, 'bug', 'browse'); + foreach($this->lang->bug->menu as $key => $menu) + { + $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID; + common::setMenuVars($this->lang->bug->menu, $key, $replace); + } + } + + /** + * Create a bug. + * + * @access public + * @return int|bool + */ + public function create() + { + $now = helper::now(); + $bug = fixer::input('post') + ->add('openedBy', $this->app->user->account) + ->add('openedDate', $now) + ->setDefault('project,story,task', 0) + ->setDefault('openedBuild', '') + ->setIF($this->post->assignedTo != '', 'assignedDate', $now) + ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->specialChars('title,keyword') + ->cleanInt('product, module, severity') + ->join('openedBuild', ',') + ->remove('files, labels') + ->get(); + $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec(); + if(!dao::isError()) + { + $bugID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('bug', $bugID); + return $bugID; + } + return false; + } + + /** + * Get bugs of a module. + * + * @param int $productID + * @param string|array $moduleIds + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getModuleBugs($productID, $moduleIds = 0, $projects, $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_BUG) + ->where('product')->eq((int)$productID) + ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi() + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get info of a bug. + * + * @param int $bugID + * @access public + * @return object + */ + public function getById($bugID) + { + $bug = $this->dao->select('t1.*, t2.name AS projectName, t3.title AS storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, t4.name AS taskName') + ->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id') + ->leftJoin(TABLE_TASK)->alias('t4')->on('t1.task = t4.id') + ->where('t1.id')->eq((int)$bugID)->fetch(); + if(!$bug) return false; + $bug->steps = $this->loadModel('file')->setImgSize($bug->steps); + foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = ''; + if($bug->mailto) + { + $bug->mailto = ltrim(trim($bug->mailto), ','); // Remove the first , + $bug->mailto = str_replace(' ', '', $bug->mailto); + $bug->mailto = rtrim($bug->mailto, ',') . ','; + $bug->mailto = str_replace(',', ', ', $bug->mailto); + } + if($bug->duplicateBug) $bug->duplicateBugTitle = $this->dao->findById($bug->duplicateBug)->from(TABLE_BUG)->fields('title')->fetch('title'); + if($bug->case) $bug->caseTitle = $this->dao->findById($bug->case)->from(TABLE_CASE)->fields('title')->fetch('title'); + if($bug->linkBug) $bug->linkBugTitles = $this->dao->select('id,title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs(); + if($bug->toStory > 0) $bug->toStoryTitle = $this->dao->findById($bug->toStory)->from(TABLE_STORY)->fields('title')->fetch('title'); + if($bug->toTask > 0) $bug->toTaskTitle = $this->dao->findById($bug->toTask)->from(TABLE_TASK)->fields('name')->fetch('name'); + $bug->files = $this->loadModel('file')->getByObject('bug', $bugID); + return $bug; + } + + /** + * getActiveBugs + * + * @param object $pager + * @param int $projectID + * @access public + * @return array + */ + public function getActiveBugs($pager, $projectID, $products) + { + return $this->dao->select('*')->from(TABLE_BUG) + ->where('status')->eq('active') + ->andWhere('toTask')->eq(0) + ->andWhere('tostory')->eq(0) + ->beginIF(!empty($products))->andWhere('product')->in($products)->fi() + ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy('id desc') + ->page($pager) + ->fetchAll(); + } + + /** + * Update a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function update($bugID) + { + $oldBug = $this->getById($bugID); + $now = helper::now(); + $bug = fixer::input('post') + ->cleanInt('product,module,severity,project,story,task') + ->specialChars('title,keyword') + ->remove('comment,files,labels') + ->setDefault('project,module,project,story,task,duplicateBug', 0) + ->setDefault('openedBuild', '') + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->join('openedBuild', ',') + ->setIF($this->post->assignedTo != $oldBug->assignedTo, 'assignedDate', $now) + ->setIF($this->post->resolvedBy != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) + ->setIF($this->post->resolution != '' and $this->post->resolvedDate == '', 'resolvedDate', $now) + ->setIF($this->post->resolution != '' and $this->post->resolvedBy == '', 'resolvedBy', $this->app->user->account) + ->setIF($this->post->closedBy != '' and $this->post->closedDate == '', 'closedDate', $now) + ->setIF($this->post->closedDate != '' and $this->post->closedBy == '', 'closedBy', $this->app->user->account) + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedTo', 'closed') + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'assignedDate', $now) + ->setIF($this->post->resolution != '' or $this->post->resolvedDate != '', 'status', 'resolved') + ->setIF($this->post->closedBy != '' or $this->post->closedDate != '', 'status', 'closed') + ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedTo', $oldBug->openedBy) + ->setIF(($this->post->resolution != '' or $this->post->resolvedDate != '') and $this->post->assignedTo == '', 'assignedDate', $now) + ->setIF($this->post->resolution == '' and $this->post->resolvedDate =='', 'status', 'active') + ->setIF($this->post->resolution != '', 'confirmed', 1) + ->setIF($this->post->story != false and $this->post->story != $oldBug->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug) + ->autoCheck() + ->batchCheck($this->config->bug->edit->requiredFields, 'notempty') + ->checkIF($bug->resolvedBy, 'resolution', 'notempty') + ->checkIF($bug->closedBy, 'resolution', 'notempty') + ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') + ->where('id')->eq((int)$bugID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldBug, $bug); + } + + /** + * Confirm a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function confirm($bugID) + { + $now = helper::now(); + $bug->confirmed = 1; + $bug->lastEditedBy = $this->app->user->account; + $bug->lastEditedDate = $now; + $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec(); + } + + /** + * Resolve a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function resolve($bugID) + { + $now = helper::now(); + $bug = fixer::input('post') + ->add('resolvedBy', $this->app->user->account) + ->add('resolvedDate', $now) + ->add('status', 'resolved') + ->add('confirmed', 1) + ->add('assignedDate', $now) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setDefault('duplicateBug', 0) + ->setDefault('assignedTo', $oldBug->openedBy) + ->remove('comment') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug) + ->autoCheck() + ->batchCheck($this->config->bug->resolve->requiredFields, 'notempty') + ->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty') + ->checkIF($bug->resolution == 'fixed', 'resolvedBuild','notempty') + ->where('id')->eq((int)$bugID) + ->exec(); + } + + /** + * Activate a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function activate($bugID) + { + $oldBug = $this->getById($bugID); + $now = helper::now(); + $bug = fixer::input('post') + ->setDefault('assignedTo', $oldBug->resolvedBy) + ->add('assignedDate', $now) + ->add('resolution', '') + ->add('status', 'active') + ->add('resolvedDate', '0000-00-00') + ->add('resolvedBy', '') + ->add('resolvedBuild', '') + ->add('closedBy', '') + ->add('closedDate', '0000-00-00') + ->add('duplicateBug', 0) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->join('openedBuild', ',') + ->remove('comment,files,labels') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); + $this->dao->update(TABLE_BUG)->set('activatedCount = activatedCount + 1')->where('id')->eq((int)$bugID)->exec(); + } + + /** + * Close a bug. + * + * @param int $bugID + * @access public + * @return void + */ + public function close($bugID) + { + $oldBug = $this->getById($bugID); + $now = helper::now(); + $bug = fixer::input('post') + ->add('assignedTo', 'closed') + ->add('assignedDate', $now) + ->add('status', 'closed') + ->add('closedBy', $this->app->user->account) + ->add('closedDate', $now) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->add('confirmed', 1) + ->remove('comment') + ->get(); + + $this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec(); + } + + /** + * Extract accounts from some bugs. + * + * @param int $bugs + * @access public + * @return array + */ + public function extractAccountsFromList($bugs) + { + $accounts = array(); + foreach($bugs as $bug) + { + if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; + if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; + if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; + if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; + if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; + } + return array_unique($accounts); + } + + /** + * Extract accounts from a bug. + * + * @param object $bug + * @access public + * @return array + */ + public function extractAccountsFromSingle($bug) + { + $accounts = array(); + if(!empty($bug->openedBy)) $accounts[] = $bug->openedBy; + if(!empty($bug->assignedTo)) $accounts[] = $bug->assignedTo; + if(!empty($bug->resolvedBy)) $accounts[] = $bug->resolvedBy; + if(!empty($bug->closedBy)) $accounts[] = $bug->closedBy; + if(!empty($bug->lastEditedBy)) $accounts[] = $bug->lastEditedBy; + return array_unique($accounts); + } + + /** + * Get bug pairs of a user. + * + * @param int $account + * @param bool $appendProduct + * @param int $limit + * @access public + * @return array + */ + public function getUserBugPairs($account, $appendProduct = true, $limit = 0) + { + $bugs = array(); + $stmt = $this->dao->select('t1.id, t1.title, t2.name as product') + ->from(TABLE_BUG)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product=t2.id') + ->where('t1.assignedTo')->eq($account) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('id desc') + ->beginIF($limit > 0)->limit($limit)->fi() + ->query(); + while($bug = $stmt->fetch()) + { + if($appendProduct) $bug->title = $bug->product . ' / ' . $bug->title; + $bugs[$bug->id] = $bug->title; + } + return $bugs; + } + + /** + * Get bugs of a project. + * + * @param int $projectID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getProjectBugs($projectID, $orderBy = 'id_desc', $pager = null, $build = 0) + { + return $this->dao->select('*')->from(TABLE_BUG) + ->where('project')->eq((int)$projectID) + ->beginIF($build != 0)->andWhere('openedBuild')->eq($build)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bug info from a result. + * + * @param int $resultID + * @param int $caseID + * @param int $version + * @access public + * @return array + */ + public function getBugInfoFromResult($resultID, $caseID = 0, $version = 0) + { + $title = ''; + $bugSteps = ''; + + $result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch(); + if($caseID > 0) + $run->case = $this->loadModel('testcase')->getById($caseID, $result->version); + else + $run = $this->loadModel('testtask')->getRunById($result->run); + if($result and $result->caseResult == 'fail') + { + $title = $run->case->title; + $caseSteps = $run->case->steps; + $stepResults = unserialize($result->stepResults); + if($run->case->precondition != '') + { + $bugSteps = "

[" . $this->lang->testcase->precondition . "]

" . "\n" . $run->case->precondition; + } + $bugSteps .= $this->lang->bug->tplStep; + if(!empty($stepResults)) + { + foreach($caseSteps as $key => $step) + { + $bugSteps .= ($key + 1) . '. ' .$step->desc . "
"; + if($stepResults[$step->id]['result'] == 'fail') + { + $bugSteps .= $this->lang->bug->tplResult; + $bugSteps .= $stepResults[$step->id]['real'] . "
"; + $bugSteps .= $this->lang->bug->tplExpect; + $bugSteps .= $step->expect; + break; + } + } + } + else + { + $bugSteps .= $this->lang->bug->tplResult; + $bugSteps .= $this->lang->bug->tplExpect; + } + } + return array('title' => $title, 'steps' => $bugSteps, 'storyID' => $run->case->story); + } + + /** + * Get report data of bugs per project + * + * @access public + * @return array + */ + public function getDataOfBugsPerProject() + { + $datas = $this->dao->select('project as name, count(project) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('project')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $projects = $this->loadModel('project')->getPairs(); + foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of bugs per module + * + * @access public + * @return array + */ + public function getDataOfBugsPerModule() + { + $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('module')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs(); + foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/'; + return $datas; + } + + /** + * Get report data of opened bugs per day. + * + * @access public + * @return array + */ + public function getDataOfOpenedBugsPerDay() + { + return $this->dao->select('DATE_FORMAT(openedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('openedDate')->fetchAll(); + } + + /** + * Get report data of resolved bugs per day. + * + * @access public + * @return array + */ + public function getDataOfResolvedBugsPerDay() + { + return $this->dao->select('DATE_FORMAT(resolvedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) + ->where($this->session->bugReportCondition)->groupBy('name') + ->having('name != 0000-00-00') + ->orderBy('resolvedDate') + ->fetchAll(); + } + + /** + * Get report data of closed bugs per day. + * + * @access public + * @return array + */ + public function getDataOfClosedBugsPerDay() + { + return $this->dao->select('DATE_FORMAT(closedDate, "%Y-%m-%d") AS name, COUNT(*) AS value')->from(TABLE_BUG) + ->where($this->session->bugReportCondition)->groupBy('name') + ->having('name != 0000-00-00') + ->orderBy('closedDate')->fetchAll(); + } + + /** + * Get report data of openeded bugs per user. + * + * @access public + * @return array + */ + public function getDataOfOpenedBugsPerUser() + { + $datas = $this->dao->select('openedBy AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + return $datas; + } + + /** + * Get report data of resolved bugs per user. + * + * @access public + * @return array + */ + public function getDataOfResolvedBugsPerUser() + { + $datas = $this->dao->select('resolvedBy AS name, COUNT(*) AS value') + ->from(TABLE_BUG)->where($this->session->bugReportCondition) + ->andWhere('resolvedBy')->ne('') + ->groupBy('name') + ->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + return $datas; + } + + /** + * Get report data of closed bugs per user. + * + * @access public + * @return array + */ + public function getDataOfClosedBugsPerUser() + { + $datas = $this->dao->select('closedBy AS name, COUNT(*) AS value') + ->from(TABLE_BUG) + ->where($this->session->bugReportCondition) + ->andWhere('closedBy')->ne('') + ->groupBy('name') + ->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + return $datas; + } + + /** + * Get report data of bugs per severity. + * + * @access public + * @return array + */ + public function getDataOfBugsPerSeverity() + { + $datas = $this->dao->select('severity AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $severity => $data) if(isset($this->lang->bug->severityList[$severity])) $data->name = $this->lang->bug->severityList[$severity]; + return $datas; + } + + /** + * Get report data of bugs per resolution. + * + * @access public + * @return array + */ + public function getDataOfBugsPerResolution() + { + $datas = $this->dao->select('resolution AS name, COUNT(*) AS value') + ->from(TABLE_BUG) + ->where($this->session->bugReportCondition) + ->andWhere('resolution')->ne('') + ->groupBy('name')->orderBy('value DESC') + ->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $resolution => $data) if(isset($this->lang->bug->resolutionList[$resolution])) $data->name = $this->lang->bug->resolutionList[$resolution]; + return $datas; + } + + /** + * Get report data of bugs per status. + * + * @access public + * @return array + */ + public function getDataOfBugsPerStatus() + { + $datas = $this->dao->select('status AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $status => $data) if(isset($this->lang->bug->statusList[$status])) $data->name = $this->lang->bug->statusList[$status]; + return $datas; + } + + /** + * Get report data of bugs per status. + * + * @access public + * @return array + */ + public function getDataOfBugsPerActivatedCount() + { + $datas = $this->dao->select('activatedCount AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $data) $data->name = $this->lang->bug->report->bugsPerActivatedCount->graph->xAxisName . ':' . $data->name; + return $datas; + } + + /** + * Get report data of bugs per type. + * + * @access public + * @return array + */ + public function getDataOfBugsPerType() + { + $datas = $this->dao->select('type AS name, COUNT(*) AS value')->from(TABLE_BUG)->where($this->session->bugReportCondition)->groupBy('name')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $type => $data) if(isset($this->lang->bug->typeList[$type])) $data->name = $this->lang->bug->typeList[$type]; + return $datas; + } + + /** + * getDataOfBugsPerAssignedTo + * + * @access public + * @return void + */ + public function getDataOfBugsPerAssignedTo() + { + $datas = $this->dao->select('assignedTo AS name, COUNT(*) AS value') + ->from(TABLE_BUG)->where($this->session->bugReportCondition) + ->groupBy('name') + ->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + return $datas; + } + + /** + * Merge the default chart settings and the settings of current chart. + * + * @param string $chartType + * @access public + * @return void + */ + public function mergeChartOption($chartType) + { + $chartOption = $this->lang->bug->report->$chartType; + $commonOption = $this->lang->bug->report->options; + + $chartOption->graph->caption = $this->lang->bug->report->charts[$chartType]; + if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; + if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; + if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; + + /* 合并配置。*/ + foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; + } + + /** + * Get bug templates of a user. + * + * @param string $account + * @access public + * @return array + */ + public function getUserBugTemplates($account) + { + $templates = $this->dao->select('id, title, content') + ->from(TABLE_USERTPL) + ->where('account')->eq($account) + ->orderBy('id') + ->fetchAll(); + return $templates; + } + + /** + * Save user template. + * + * @access public + * @return void + */ + public function saveUserBugTemplate() + { + $template = fixer::input('post') + ->specialChars('title') + ->add('account', $this->app->user->account) + ->add('type', 'bug') + ->get(); + $this->dao->insert(TABLE_USERTPL)->data($template)->autoCheck('title, content', 'notempty')->check('title', 'unique')->exec(); + } + + /** + * Return the file => label pairs of some fields. + * + * @param string $fields + * @access public + * @return array + */ + public function getFieldPairs($fields) + { + $fields = explode(',', $fields); + foreach($fields as $key => $field) + { + $field = trim($field); + $fields[$field] = $this->lang->bug->$field; + unset($fields[$key]); + } + return $fields; + } + + /** + * Get all bugs. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getAllBugs($productID, $projects, $orderBy, $pager) + { + return $this->dao->select('*')->from(TABLE_BUG)->where('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs of assign to me. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByAssigntome($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByAssignedTo($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs of opened by me. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByOpenedbyme($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs of resolved by me. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByResolvedbyme($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs of nobody to do. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByAssigntonull($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByAssignedTo('')->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs the status is active or unclosed. + * + * @param int $productID + * @param array $projects + * @param string $status + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByStatus($productID, $projects, $status, $orderBy, $pager) + { + return $this->dao->select('*')->from(TABLE_BUG) + ->where('project')->in(array_keys($projects)) + ->andWhere('product')->eq($productID) + ->beginIF($status == 'unclosed')->andWhere('status')->ne('closed')->fi() + ->beginIF($status == 'unresolved')->andWhere('status')->eq('active')->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get unresolve bugs for long time. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByLonglifebugs($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByLastEditedDate("<", date(DT_DATE1, strtotime('-7 days')))->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->andWhere('openedDate')->lt(date(DT_DATE1,strtotime('-7 days'))) + ->andWhere('deleted')->eq(0) + ->andWhere('status')->ne('closed')->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get postponed bugs. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByPostponedbugs($productID, $projects, $orderBy, $pager) + { + return $this->dao->findByResolution('postponed')->from(TABLE_BUG)->andWhere('product')->eq($productID) + ->andWhere('project')->in(array_keys($projects)) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get bugs need confirm. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByNeedconfirm($productID, $projects, $orderBy, $pager) + { + return $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_BUG)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->where("t2.status = 'active'") + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.version > t1.storyVersion') + ->andWhere('t1.project')->in(array_keys($projects)) + ->orderBy($orderBy) + ->fetchAll(); + } + + /** + * Get bugs by search. + * + * @param int $productID + * @param array $projects + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getBySearch($productID, $projects, $queryID, $orderBy, $pager) + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('bugQuery', $query->sql); + $this->session->set('bugForm', $query->form); + } + else + { + $this->session->set('bugQuery', ' 1 = 1'); + } + } + else + { + if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); + } + + /* check the purview of projects.*/ + if(strpos($this->session->bugQuery, '`project`') === false) + { + $var = $this->session->bugQuery . 'AND `project`' . helper::dbIN(array_keys($projects)); + $this->session->set('bugQuery', "$var"); + } + + $bugQuery = str_replace("`product` = 'all'", '1', $this->session->bugQuery); // Search all product. + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + return $bugs; + } + + /** + * Form customed bugs. + * + * @param array $bugs + * @access public + * @return array + */ + public function formCustomedBugs($bugs) + { + /* Get related objects id lists. */ + $relatedModuleIdList = array(); + $relatedStoryIdList = array(); + $relatedTaskIdList = array(); + $relatedCaseIdList = array(); + $relatedProjectIdList = array(); + + foreach($bugs as $bug) + { + $relatedModuleIdList[$bug->module] = $bug->module; + $relatedStoryIdList[$bug->story] = $bug->story; + $relatedTaskIdList[$bug->task] = $bug->task; + $relatedCaseIdList[$bug->case] = $bug->case; + $relatedProjectIdList[$bug->project] = $bug->project; + + /* Get related objects title or names. */ + $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); + $relatedStories = $this->dao->select('id, title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedTasks = $this->dao->select('id, name')->from(TABLE_TASK)->where('id')->in($relatedTaskIdList)->fetchPairs(); + $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); + $relatedProjects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->in($relatedProjectIdList)->fetchPairs(); + + /* fill some field with useful value. */ + if(isset($relatedModules[$bug->module])) $bug->module = $relatedModules[$bug->module]; + if(isset($relatedStories[$bug->story])) $bug->story = $relatedStories[$bug->story]; + if(isset($relatedTasks[$bug->task])) $bug->task = $relatedTasks[$bug->task]; + if(isset($relatedCases[$bug->case])) $bug->case = $relatedCases[$bug->case]; + if(isset($relatedProjects[$bug->project])) $bug->project = $relatedProjects[$bug->project]; + } + return $bugs; + } +} diff --git a/module/bug/view/activate.html.php b/module/bug/view/activate.html.php index a09b694da7..8d056326c9 100644 --- a/module/bug/view/activate.html.php +++ b/module/bug/view/activate.html.php @@ -1,43 +1,43 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
- - - - - - - - - - - - - - - - - - - - - -
title;?>
bug->assignedTo;?>resolvedBy, 'class=select-3');?>
bug->openedBuild;?>openedBuild, 'size=4 multiple=multiple class=select-3');?>
comment;?>
bug->files;?>fetch('file', 'buildform');?>
- - -
- -
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+ + + + + + + + + + + + + + + + + + + + + +
title;?>
bug->assignedTo;?>resolvedBy, 'class=select-3');?>
bug->openedBuild;?>openedBuild, 'size=4 multiple=multiple class=select-3');?>
comment;?>
bug->files;?>fetch('file', 'buildform');?>
+ + +
+ +
+ diff --git a/module/bug/view/browse.custom.html.php b/module/bug/view/browse.custom.html.php index 8c876607b3..ec6f230b47 100644 --- a/module/bug/view/browse.custom.html.php +++ b/module/bug/view/browse.custom.html.php @@ -1,71 +1,71 @@ - - - - - - -
- -
-
- -
- createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?> -
-
-
-
- recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - id");?> - - - - - - - - - -
bug->$fieldName);?>actions;?>
- $fieldName); - } - elseif(preg_match('/assignedTo|by/i', $fieldName)) - { - echo $users[$bug->$fieldName]; - } - elseif(preg_match('/^(severity|pri|resolution|os|type|browse|status|confirmed)$/i', $fieldName)) - { - $key = $fieldName . 'List'; - $list = $lang->bug->$key; - echo $list[$bug->$fieldName]; - } - else - { - echo !($bug->$fieldName == '0') ? $bug->$fieldName : ''; - } - ?> - - id"; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - ?> - -
show();?>
-
- + + + + + + +
+ +
+
+ +
+ createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?> +
+
+
+
+ recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + id");?> + + + + + + + + + +
bug->$fieldName);?>actions;?>
+ $fieldName); + } + elseif(preg_match('/assignedTo|by/i', $fieldName)) + { + echo $users[$bug->$fieldName]; + } + elseif(preg_match('/^(severity|pri|resolution|os|type|browse|status|confirmed)$/i', $fieldName)) + { + $key = $fieldName . 'List'; + $list = $lang->bug->$key; + echo $list[$bug->$fieldName]; + } + else + { + echo !($bug->$fieldName == '0') ? $bug->$fieldName : ''; + } + ?> + + id"; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + ?> + +
show();?>
+
+ diff --git a/module/bug/view/browse.html.php b/module/bug/view/browse.html.php index 0787e6ab7f..e64a4b6f51 100644 --- a/module/bug/view/browse.html.php +++ b/module/bug/view/browse.html.php @@ -1,175 +1,175 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
-
- " . $lang->bug->moduleBugs . " "; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToNull¶m=0"), $lang->bug->assignToNull) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unResolved¶m=0"), $lang->bug->unResolved) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unclosed¶m=0"), $lang->bug->unclosed) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . ""; - echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->bug->needConfirm) . ""; - echo "{$lang->bug->byQuery} "; - ?> -
-
- export, '', 'class="export"'); ?> - bug->customFields, '', "class='iframe'"); ?> - bug->report->common); ?> - bug->create); ?> -
-
-
'>
- - - - - - - - - -
-
-
- -
- createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?> -
-
-
- recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - id");?> - - status == 'active' ? 'active' . $bug->severity : $bug->status;?> - - - - - confirmed;?> - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - cookie->windowWidth >= $this->config->wideSize):?> - - - - - - - - - - - cookie->windowWidth > $this->config->wideSize ? 12 : 9;?> - - - -
idAB);?> bug->severityAB);?> priAB);?>bug->title);?>bug->statusAB);?>bug->story);?>actions;?>openedByAB);?> bug->openedDateAB);?>assignedToAB);?>bug->resolvedByAB);?>bug->resolutionAB);?> bug->resolvedDateAB);?>actions;?>
bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>[{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>bug->statusList[$bug->status];?>createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin')?>openedBy];?>openedDate, 5, 11)?>assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>resolvedDate, 5, 11)?> - id"; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - if($this->cookie->windowWidth >= $this->config->wideSize) common::printLink('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $lang->bug->buttonCopy); - ?> -
-
- bug->statusList as $status => $label) - { - if($status != 'active') - { - echo " $label "; - continue; - } - rsort($this->lang->bug->severityList); - foreach($this->lang->bug->severityList as $severity) - { - echo " {$lang->bug->severity}:$severity "; - } - } - ?> -
-
show();?>
-
-
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
+
+ " . $lang->bug->moduleBugs . " "; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToMe¶m=0"), $lang->bug->assignToMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=openedByMe¶m=0"), $lang->bug->openedByMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=resolvedByMe¶m=0"), $lang->bug->resolvedByMe) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=assignToNull¶m=0"), $lang->bug->assignToNull) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unResolved¶m=0"), $lang->bug->unResolved) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=unclosed¶m=0"), $lang->bug->unclosed) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=longLifeBugs¶m=0"), $lang->bug->longLifeBugs) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=postponedBugs¶m=0"), $lang->bug->postponedBugs) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->bug->allBugs) . ""; + echo "" . html::a($this->createLink('bug', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->bug->needConfirm) . ""; + echo "{$lang->bug->byQuery} "; + ?> +
+
+ export, '', 'class="export"'); ?> + bug->customFields, '', "class='iframe'"); ?> + bug->report->common); ?> + bug->create); ?> +
+
+
'>
+ + + + + + + + + +
+
+
+ +
+ createLink('tree', 'browse', "productID=$productID&view=bug"), $lang->tree->manage);?> +
+
+
+ recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + id");?> + + status == 'active' ? 'active' . $bug->severity : $bug->status;?> + + + + + confirmed;?> + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + cookie->windowWidth >= $this->config->wideSize):?> + + + + + + + + + + + cookie->windowWidth > $this->config->wideSize ? 12 : 9;?> + + + +
idAB);?> bug->severityAB);?> priAB);?>bug->title);?>bug->statusAB);?>bug->story);?>actions;?>openedByAB);?> bug->openedDateAB);?>assignedToAB);?>bug->resolvedByAB);?>bug->resolutionAB);?> bug->resolvedDateAB);?>actions;?>
bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>[{$lang->bug->confirmedList[$bug->confirmed]}] " . html::a($bugLink, $bug->title);?>bug->statusList[$bug->status];?>createLink('story', 'view', "stoyID=$bug->story"), $bug->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin')?>openedBy];?>openedDate, 5, 11)?>assignedTo == $this->app->user->account) echo 'class="red"';?>>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>resolvedDate, 5, 11)?> + id"; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if($this->cookie->windowWidth >= $this->config->wideSize) common::printLink('bug', 'create', "product=$bug->product&extra=bugID=$bug->id", $lang->bug->buttonCopy); + ?> +
+
+ bug->statusList as $status => $label) + { + if($status != 'active') + { + echo " $label "; + continue; + } + rsort($this->lang->bug->severityList); + foreach($this->lang->bug->severityList as $severity) + { + echo " {$lang->bug->severity}:$severity "; + } + } + ?> +
+
show();?>
+
+
+ diff --git a/module/bug/view/close.html.php b/module/bug/view/close.html.php index c1ff9253fa..678f8e599c 100644 --- a/module/bug/view/close.html.php +++ b/module/bug/view/close.html.php @@ -1,31 +1,31 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
- - - - - - - - - -
title;?>
comment;?>
- - -
- -
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+ + + + + + + + + +
title;?>
comment;?>
+ + +
+ +
+ diff --git a/module/bug/view/confirmbug.html.php b/module/bug/view/confirmbug.html.php index 0aa2fc52a1..07c68591c8 100755 --- a/module/bug/view/confirmbug.html.php +++ b/module/bug/view/confirmbug.html.php @@ -1,31 +1,31 @@ - - * @package bug - * @version $Id: resolve.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $ - * @link http://www.zentao.net - */ -?> - -
- - - - - - - - - -
title;?>
comment;?>
- bug->buttonConfirm);?> - -
- -
- + + * @package bug + * @version $Id: resolve.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $ + * @link http://www.zentao.net + */ +?> + +
+ + + + + + + + + +
title;?>
comment;?>
+ bug->buttonConfirm);?> + +
+ +
+ diff --git a/module/bug/view/create.html.php b/module/bug/view/create.html.php index 54c7466f7c..5571d8f7ec 100644 --- a/module/bug/view/create.html.php +++ b/module/bug/view/create.html.php @@ -1,102 +1,102 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bug->create;?>
bug->lblProductAndModule;?> - - -
bug->project;?>
bug->openedBuild;?> - -
bug->lblAssignedTo;?>
bug->title;?>
bug->steps;?> - - - - - -
fetch('bug', 'buildTemplates');?>
-
bug->lblStory;?> - -
bug->task;?>
bug->lblTypeAndSeverity;?> - bug->typeList, $type, 'class=select-2');?> - bug->severityList, $severity, 'class=select-2');?> -
bug->lblSystemBrowserAndHardware;?> - bug->osList, $os, 'class=select-2');?> - bug->browserList, $browser, 'class=select-2');?> -
bug->lblMailto;?>
bug->keywords;?>
bug->files;?>fetch('file', 'buildform', 'fileCount=2&percent=0.85');?>
- -
-
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->create;?>
bug->lblProductAndModule;?> + + +
bug->project;?>
bug->openedBuild;?> + +
bug->lblAssignedTo;?>
bug->title;?>
bug->steps;?> + + + + + +
fetch('bug', 'buildTemplates');?>
+
bug->lblStory;?> + +
bug->task;?>
bug->lblTypeAndSeverity;?> + bug->typeList, $type, 'class=select-2');?> + bug->severityList, $severity, 'class=select-2');?> +
bug->lblSystemBrowserAndHardware;?> + bug->osList, $os, 'class=select-2');?> + bug->browserList, $browser, 'class=select-2');?> +
bug->lblMailto;?>
bug->keywords;?>
bug->files;?>fetch('file', 'buildform', 'fileCount=2&percent=0.85');?>
+ +
+
+ diff --git a/module/bug/view/customfields.html.php b/module/bug/view/customfields.html.php index cc6f2df478..bcef9b5dbe 100644 --- a/module/bug/view/customfields.html.php +++ b/module/bug/view/customfields.html.php @@ -1,49 +1,49 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
- - - - - - - - - - - - - - - -
bug->customFields;?>
bug->lblAllFields;?>bug->lblCustomFields;?>
- - - ', "onclick=\"addItem('allFields', 'customFields')\"") . '
'; - echo html::commonButton('<', "onclick=delItem('customFields')") . '
'; - ?> -
- '; - echo html::commonButton('-', "onclick=downItem('customFields')") . '
'; - echo html::commonButton($lang->bug->restoreDefault, "onclick=restoreDefault()") . '
'; - ?> -
-
- + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
+ + + + + + + + + + + + + + + +
bug->customFields;?>
bug->lblAllFields;?>bug->lblCustomFields;?>
+ + + ', "onclick=\"addItem('allFields', 'customFields')\"") . '
'; + echo html::commonButton('<', "onclick=delItem('customFields')") . '
'; + ?> +
+ '; + echo html::commonButton('-', "onclick=downItem('customFields')") . '
'; + echo html::commonButton($lang->bug->restoreDefault, "onclick=restoreDefault()") . '
'; + ?> +
+
+ diff --git a/module/bug/view/edit.html.php b/module/bug/view/edit.html.php index e15296c932..6cd6689826 100644 --- a/module/bug/view/edit.html.php +++ b/module/bug/view/edit.html.php @@ -1,206 +1,206 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
-
-
- BUG #id . $lang->colon;?> - title), 'class=text-1');?> -
-
-
- - - - - - - -
- - -
-
- bug->legendSteps;?> -
steps), "rows='12'");?>
-
-
- bug->legendComment;?> - -
-
- bug->legendAttatch;?> - fetch('file', 'buildform', 'filecount=2');?> -
-
- session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product"); - echo html::linkButton($lang->goback, $browseLink); - ?> -
-
- -
-
- bug->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bug->product;?> - -
bug->module;?> - -
bug->type;?>bug->typeList, $bug->type, 'class=select-3');?> -
bug->severity;?>bug->severityList, $bug->severity, 'class=select-3');?> -
bug->pri;?>bug->priList, $bug->pri, 'class=select-3');?> -
bug->status;?>bug->statusList, $bug->status, 'class=select-3');?>
bug->confirmed;?>bug->confirmedList[$bug->confirmed];?>
bug->assignedTo;?>assignedTo, 'class=select-3');?>
bug->os;?>bug->osList, $bug->os, 'class=select-3');?>
bug->browser;?>bug->browserList, $bug->browser, 'class=select-3');?>
bug->keywords;?>keywords, 'class="text-3"');?>
-
- -
- bug->legendPrjStoryTask;?> - - - - - - - - - - - - - -
bug->project;?>project, 'class=select-3 onchange=loadProjectRelated(this.value)');?>
bug->story;?>
story, "class=select-3");?>
- -
bug->task;?>
task, 'class=select-3');?>
- -
-
- -
- bug->legendLife;?> - - - - - - - - - - - - - - - - - - - - - - - - - - resolution != 'duplicate') echo "style='display:none'";?>> - - - - - - - - - - - -
bug->openedBy;?>openedBy];?>
bug->openedBuild;?>openedBuild, 'size=4 multiple=multiple class=select-3');?>
bug->resolvedBy;?>resolvedBy, 'class=select-3');?>
bug->resolvedDate;?>resolvedDate, 'class=text-3');?>
bug->resolvedBuild;?>resolvedBuild, 'class=select-3');?>
bug->resolution;?>bug->resolutionList, $bug->resolution, 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->duplicateBug;?>duplicateBug, 'class=text-3');?>
bug->closedBy;?>closedBy, 'class=select-3');?>
bug->closedDate;?>closedDate, 'class=text-3');?>
-
-
- bug->legendMisc;?> - - - - - - - - - - - - - -
bug->mailto;?>mailto, 'class="text-3"');?>
bug->linkBug;?>linkBug, 'class="text-3"');?>
bug->case;?>case, 'class="text-3"');?>
-
-
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
+
+ BUG #id . $lang->colon;?> + title), 'class=text-1');?> +
+
+
+ + + + + + + +
+ + +
+
+ bug->legendSteps;?> +
steps), "rows='12'");?>
+
+
+ bug->legendComment;?> + +
+
+ bug->legendAttatch;?> + fetch('file', 'buildform', 'filecount=2');?> +
+
+ session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product"); + echo html::linkButton($lang->goback, $browseLink); + ?> +
+
+ +
+
+ bug->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->product;?> + +
bug->module;?> + +
bug->type;?>bug->typeList, $bug->type, 'class=select-3');?> +
bug->severity;?>bug->severityList, $bug->severity, 'class=select-3');?> +
bug->pri;?>bug->priList, $bug->pri, 'class=select-3');?> +
bug->status;?>bug->statusList, $bug->status, 'class=select-3');?>
bug->confirmed;?>bug->confirmedList[$bug->confirmed];?>
bug->assignedTo;?>assignedTo, 'class=select-3');?>
bug->os;?>bug->osList, $bug->os, 'class=select-3');?>
bug->browser;?>bug->browserList, $bug->browser, 'class=select-3');?>
bug->keywords;?>keywords, 'class="text-3"');?>
+
+ +
+ bug->legendPrjStoryTask;?> + + + + + + + + + + + + + +
bug->project;?>project, 'class=select-3 onchange=loadProjectRelated(this.value)');?>
bug->story;?>
story, "class=select-3");?>
+ +
bug->task;?>
task, 'class=select-3');?>
+ +
+
+ +
+ bug->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + + resolution != 'duplicate') echo "style='display:none'";?>> + + + + + + + + + + + +
bug->openedBy;?>openedBy];?>
bug->openedBuild;?>openedBuild, 'size=4 multiple=multiple class=select-3');?>
bug->resolvedBy;?>resolvedBy, 'class=select-3');?>
bug->resolvedDate;?>resolvedDate, 'class=text-3');?>
bug->resolvedBuild;?>resolvedBuild, 'class=select-3');?>
bug->resolution;?>bug->resolutionList, $bug->resolution, 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->duplicateBug;?>duplicateBug, 'class=text-3');?>
bug->closedBy;?>closedBy, 'class=select-3');?>
bug->closedDate;?>closedDate, 'class=text-3');?>
+
+
+ bug->legendMisc;?> + + + + + + + + + + + + + +
bug->mailto;?>mailto, 'class="text-3"');?>
bug->linkBug;?>linkBug, 'class="text-3"');?>
bug->case;?>case, 'class="text-3"');?>
+
+
+ diff --git a/module/bug/view/export.html.php b/module/bug/view/export.html.php index 228c01d5da..3f1bb625f8 100755 --- a/module/bug/view/export.html.php +++ b/module/bug/view/export.html.php @@ -1,13 +1,13 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + diff --git a/module/bug/view/report.html.php b/module/bug/view/report.html.php index 1932051a27..f5250a10fd 100644 --- a/module/bug/view/report.html.php +++ b/module/bug/view/report.html.php @@ -1,62 +1,62 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
-
bug->report->common;?>
-
goback); ?>
-
- - - - - - - -
-
bug->report->select;?>
-
- - bug->report->charts, $checkedCharts);?> - - -

- bug->report->create);?> -
-
- - - $chartContent):?> - - - - - -
bug->report->common;?>
- - - - - - - $data):?> - - - - - - -
report->item;?>report->value;?>report->percent;?>
name;?>value;?>percent * 100) . '%';?>
-
-
- - + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
bug->report->common;?>
+
goback); ?>
+
+ + + + + + + +
+
bug->report->select;?>
+
+ + bug->report->charts, $checkedCharts);?> + + +

+ bug->report->create);?> +
+
+ + + $chartContent):?> + + + + + +
bug->report->common;?>
+ + + + + + + $data):?> + + + + + + +
report->item;?>report->value;?>report->percent;?>
name;?>value;?>percent * 100) . '%';?>
+
+
+ + diff --git a/module/bug/view/resolve.html.php b/module/bug/view/resolve.html.php index 1ff035e6a9..a1c5db5879 100644 --- a/module/bug/view/resolve.html.php +++ b/module/bug/view/resolve.html.php @@ -1,47 +1,47 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - -
title;?>
bug->resolution;?>bug->resolutionList['tostory']); echo html::select('resolution', $lang->bug->resolutionList, '', 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->resolvedBuild;?>
bug->assignedTo;?>openedBy, 'class=select-3');?>
comment;?>
- - -
- -
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
title;?>
bug->resolution;?>bug->resolutionList['tostory']); echo html::select('resolution', $lang->bug->resolutionList, '', 'class=select-3 onchange=setDuplicate(this.value)');?>
bug->resolvedBuild;?>
bug->assignedTo;?>openedBy, 'class=select-3');?>
comment;?>
+ + +
+ +
+ diff --git a/module/bug/view/sendmail.html.php b/module/bug/view/sendmail.html.php index e5cb9603e3..a474addb0a 100644 --- a/module/bug/view/sendmail.html.php +++ b/module/bug/view/sendmail.html.php @@ -1,22 +1,22 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
- BUG #id . "=>$bug->assignedTo " . html::a(common::getSysURL() . $this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?> -
+ + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
+ BUG #id . "=>$bug->assignedTo " . html::a(common::getSysURL() . $this->createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?> +
diff --git a/module/bug/view/view.html.php b/module/bug/view/view.html.php index 4705920f2c..24a0e4f5df 100644 --- a/module/bug/view/view.html.php +++ b/module/bug/view/view.html.php @@ -1,272 +1,272 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
-
deleted) echo "class='deleted'";?>>BUG #id . $lang->colon . $bug->title;?>
-
- session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product"); - $params = "bugID=$bug->id"; - $copyParams = "productID=$productID&extras=bugID=$bug->id"; - $convertParams = "productID=$productID&moduleID=0&from=bug&bugID=$bug->id"; - if(!$bug->deleted) - { - if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' '; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; - common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy); - if($bug->status == 'active' and common::hasPriv('story', 'create')) - { - common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' '; - } - else - { - echo $lang->bug->toStory . ' '; - } - common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase); - common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
-
- - - - - - - -
-
- bug->legendSteps;?> -
[', '

[', $bug->steps);?>

-
- fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true'));?> - -
- deleted) - { - if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' '; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; - common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy); - if($bug->status == 'active' and common::hasPriv('bug', 'resolve')) - { - common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' '; - } - else - { - echo $lang->bug->toStory . ' '; - } - common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase); - common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
- -
-
- bug->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bug->product;?>product", $productName)) echo $productName;?> -
bug->module;?> - $module) - { - if(!common::printLink('bug', 'browse', "productID=$bug->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; - if(isset($modulePath[$key + 1])) echo $lang->arrow; - } - ?> -
bug->type;?>bug->typeList[$bug->type])) echo $lang->bug->typeList[$bug->type]; else echo $bug->type;?>
bug->severity;?>bug->severityList[$bug->severity];?>
bug->pri;?>bug->priList[$bug->pri];?>
bug->status;?>bug->statusList[$bug->status];?>
bug->activatedCount;?>activatedCount;?>
bug->confirmed;?>bug->confirmedList[$bug->confirmed];?>
bug->lblAssignedTo;?>assignedTo) echo $users[$bug->assignedTo] . $lang->at . $bug->assignedDate;?>
bug->os;?>bug->osList[$bug->os];?>
bug->browser;?>bug->browserList[$bug->browser];?>
bug->keywords;?>keywords;?>
-
-
- bug->legendLife;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bug->openedBy;?> openedBy] . $lang->at . $bug->openedDate;?>
bug->openedBuild;?> - openedBuild) - { - $openedBuilds = explode(',', $bug->openedBuild); - foreach($openedBuilds as $openedBuild) isset($builds[$openedBuild]) ? print($builds[$openedBuild] . '
') : print($openedBuild . '
'); - } - else - { - echo $bug->openedBuild; - } - ?> -
bug->lblResolved;?>resolvedBy) echo $users[$bug->resolvedBy] . $lang->at . $bug->resolvedDate;?> -
bug->resolvedBuild;?>resolvedBuild])) echo $builds[$bug->resolvedBuild]; else echo $bug->resolvedBuild;?>
bug->resolution;?> - bug->resolutionList[$bug->resolution]; - if(isset($bug->duplicateBugTitle)) echo " #$bug->duplicateBug:" . html::a($this->createLink('bug', 'view', "bugID=$bug->duplicateBug"), $bug->duplicateBugTitle); - ?> -
bug->closedBy;?>closedBy) echo $users[$bug->closedBy] . $lang->at . $bug->closedDate;?>
bug->lblLastEdited;?>lastEditedBy) echo $users[$bug->lastEditedBy] . $lang->at . $bug->lastEditedDate?>
-
- -
- bug->legendPrjStoryTask;?> - - - - - - - - - - - - - -
bug->project;?>project) echo html::a($this->createLink('project', 'browse', "projectid=$bug->project"), $bug->projectName);?>
bug->story;?> - story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story"), $bug->storyTitle); - if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion) - { - echo "({$lang->story->changed} "; - echo html::a($this->createLink('bug', 'confirmStoryChange', "bugID=$bug->id"), $lang->confirm, 'hiddenwin'); - echo ")"; - } - ?> -
bug->task;?>task) echo html::a($this->createLink('task', 'view', "taskID=$bug->task"), $bug->taskName);?>
-
-
- bug->legendMisc;?> - - - - - - - - - - - - - - - - - - - - - -
bug->mailto;?>mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
bug->linkBug;?> - linkBugTitles)) - { - foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle) - { - echo html::a($this->createLink('bug', 'view', "bugID=$linkBugID"), "#$linkBugID $linkBugTitle", '_blank') . '
'; - } - } - ?> -
bug->case;?>caseTitle)) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?>
bug->toStory;?>toStory != 0) echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?>
bug->toTask;?>toTask != 0) echo html::a($this->createLink('bug', 'view', "bugID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?>
-
-
- + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+
deleted) echo "class='deleted'";?>>BUG #id . $lang->colon . $bug->title;?>
+
+ session->bugList != false ? $app->session->bugList : inlink('browse', "productID=$bug->product"); + $params = "bugID=$bug->id"; + $copyParams = "productID=$productID&extras=bugID=$bug->id"; + $convertParams = "productID=$productID&moduleID=0&from=bug&bugID=$bug->id"; + if(!$bug->deleted) + { + if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' '; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy); + if($bug->status == 'active' and common::hasPriv('story', 'create')) + { + common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' '; + } + else + { + echo $lang->bug->toStory . ' '; + } + common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase); + common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
+
+ + + + + + + +
+
+ bug->legendSteps;?> +
[', '

[', $bug->steps);?>

+
+ fetch('file', 'printFiles', array('files' => $bug->files, 'fieldset' => 'true'));?> + +
+ deleted) + { + if(!($bug->status == 'active' and $bug->confirmed == 0 and common::printLink('bug', 'confirmBug', $params, $lang->bug->buttonConfirm))) echo $lang->bug->buttonConfirm . ' '; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + if(common::hasPriv('bug', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + if(!(($bug->status == 'closed' or $bug->status == 'resolved') and $bug->resolution != 'tostory' and common::printLink('bug', 'activate', $params, $lang->bug->buttonActivate))) echo $lang->bug->buttonActivate . ' '; + common::printLink('bug', 'create', $copyParams, $lang->bug->buttonCopy); + if($bug->status == 'active' and common::hasPriv('bug', 'resolve')) + { + common::printLink('story', 'create', "product=$bug->product&module=0&story=0&project=0&bugID=$bug->id", $lang->bug->toStory) . ' '; + } + else + { + echo $lang->bug->toStory . ' '; + } + common::printLink('testcase', 'create', $convertParams, $lang->bug->buttonCreateTestcase); + common::printLink('bug', 'delete', $params, $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
+ +
+
+ bug->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->product;?>product", $productName)) echo $productName;?> +
bug->module;?> + $module) + { + if(!common::printLink('bug', 'browse', "productID=$bug->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; + if(isset($modulePath[$key + 1])) echo $lang->arrow; + } + ?> +
bug->type;?>bug->typeList[$bug->type])) echo $lang->bug->typeList[$bug->type]; else echo $bug->type;?>
bug->severity;?>bug->severityList[$bug->severity];?>
bug->pri;?>bug->priList[$bug->pri];?>
bug->status;?>bug->statusList[$bug->status];?>
bug->activatedCount;?>activatedCount;?>
bug->confirmed;?>bug->confirmedList[$bug->confirmed];?>
bug->lblAssignedTo;?>assignedTo) echo $users[$bug->assignedTo] . $lang->at . $bug->assignedDate;?>
bug->os;?>bug->osList[$bug->os];?>
bug->browser;?>bug->browserList[$bug->browser];?>
bug->keywords;?>keywords;?>
+
+
+ bug->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bug->openedBy;?> openedBy] . $lang->at . $bug->openedDate;?>
bug->openedBuild;?> + openedBuild) + { + $openedBuilds = explode(',', $bug->openedBuild); + foreach($openedBuilds as $openedBuild) isset($builds[$openedBuild]) ? print($builds[$openedBuild] . '
') : print($openedBuild . '
'); + } + else + { + echo $bug->openedBuild; + } + ?> +
bug->lblResolved;?>resolvedBy) echo $users[$bug->resolvedBy] . $lang->at . $bug->resolvedDate;?> +
bug->resolvedBuild;?>resolvedBuild])) echo $builds[$bug->resolvedBuild]; else echo $bug->resolvedBuild;?>
bug->resolution;?> + bug->resolutionList[$bug->resolution]; + if(isset($bug->duplicateBugTitle)) echo " #$bug->duplicateBug:" . html::a($this->createLink('bug', 'view', "bugID=$bug->duplicateBug"), $bug->duplicateBugTitle); + ?> +
bug->closedBy;?>closedBy) echo $users[$bug->closedBy] . $lang->at . $bug->closedDate;?>
bug->lblLastEdited;?>lastEditedBy) echo $users[$bug->lastEditedBy] . $lang->at . $bug->lastEditedDate?>
+
+ +
+ bug->legendPrjStoryTask;?> + + + + + + + + + + + + + +
bug->project;?>project) echo html::a($this->createLink('project', 'browse', "projectid=$bug->project"), $bug->projectName);?>
bug->story;?> + story) echo html::a($this->createLink('story', 'view', "storyID=$bug->story"), $bug->storyTitle); + if($bug->storyStatus == 'active' and $bug->latestStoryVersion > $bug->storyVersion) + { + echo "({$lang->story->changed} "; + echo html::a($this->createLink('bug', 'confirmStoryChange', "bugID=$bug->id"), $lang->confirm, 'hiddenwin'); + echo ")"; + } + ?> +
bug->task;?>task) echo html::a($this->createLink('task', 'view', "taskID=$bug->task"), $bug->taskName);?>
+
+
+ bug->legendMisc;?> + + + + + + + + + + + + + + + + + + + + + +
bug->mailto;?>mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
bug->linkBug;?> + linkBugTitles)) + { + foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle) + { + echo html::a($this->createLink('bug', 'view', "bugID=$linkBugID"), "#$linkBugID $linkBugTitle", '_blank') . '
'; + } + } + ?> +
bug->case;?>caseTitle)) echo html::a($this->createLink('testcase', 'view', "caseID=$bug->case"), "#$bug->case $bug->caseTitle", '_blank');?>
bug->toStory;?>toStory != 0) echo html::a($this->createLink('story', 'view', "storyID=$bug->toStory"), "#$bug->toStory $bug->toStoryTitle", '_blank');?>
bug->toTask;?>toTask != 0) echo html::a($this->createLink('bug', 'view', "bugID=$bug->toTask"), "#$bug->toTask $bug->toTaskTitle", '_blank');?>
+
+
+ diff --git a/module/build/control.php b/module/build/control.php index 0f06d9560a..3750dd1074 100644 --- a/module/build/control.php +++ b/module/build/control.php @@ -1,186 +1,186 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -class build extends control -{ - /** - * Create a buld. - * - * @param int $projectID - * @access public - * @return void - */ - public function create($projectID) - { - if(!empty($_POST)) - { - $buildID = $this->build->create($projectID); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('build', $buildID, 'opened'); - die(js::locate($this->createLink('project', 'build', "project=$projectID"), 'parent')); - } - - /* Load these models. */ - $this->loadModel('story'); - $this->loadModel('bug'); - $this->loadModel('task'); - $this->loadModel('project'); - $this->loadModel('user'); - - /* Set menu. */ - $this->project->setMenu($this->project->getPairs(), $projectID); - - /* Get stories and bugs. */ - $orderBy = 'status_asc, stage_asc, id_desc'; - $stories = $this->story->getProjectStories($projectID, $orderBy); - $bugs = $this->project->getResolvedBugs($projectID); - - /* Assign. */ - $this->view->header->title = $this->lang->build->create; - $this->view->products = $this->project->getProducts($projectID); - $this->view->projectID = $projectID; - $this->view->users = $this->user->getPairs(); - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->orderBy = $orderBy; - $this->display(); - } - - /** - * Edit a build. - * - * @param int $buildID - * @access public - * @return void - */ - public function edit($buildID) - { - if(!empty($_POST)) - { - $changes = $this->build->update($buildID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('build', $buildID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "buildID=$buildID"), 'parent')); - } - - $this->loadModel('story'); - $this->loadModel('bug'); - $this->loadModel('project'); - - /* Set menu. */ - $build = $this->build->getById((int)$buildID); - $this->project->setMenu($this->project->getPairs(), $build->project); - - /* Get stories and bugs. */ - $orderBy = 'status_asc, stage_asc, id_desc'; - $stories = $this->story->getProjectStories($build->project, $orderBy); - $bugs = $this->project->getResolvedBugs($build->project); - - /* Assign. */ - $this->view->header->title = $this->lang->build->edit; - $this->view->position[] = $this->lang->build->edit; - $this->view->products = $this->project->getProducts($build->project); - $this->view->users = $this->loadModel('user')->getPairs(); - $this->view->build = $build; - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->orderBy = $orderBy; - $this->display(); - } - - /** - * View a build. - * - * @param int $buildID - * @access public - * @return void - */ - public function view($buildID) - { - $this->loadModel('story'); - $this->loadModel('bug'); - - /* Set menu. */ - $build = $this->build->getById((int)$buildID); - if(!$build) die(js::error($this->lang->notFound) . js::locate('back')); - $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->fetchAll(); - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->fetchAll(); - - $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project); - - /* Assign. */ - $this->view->header->title = $this->lang->build->view; - $this->view->position[] = $this->lang->build->view; - $this->view->products = $this->project->getProducts($build->project); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->build = $build; - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->actions = $this->loadModel('action')->getList('build', $buildID); - $this->display(); - } - - /** - * Delete a build. - * - * @param int $buildID - * @param string $confirm yes|noe - * @access public - * @return void - */ - public function delete($buildID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes"))); - } - else - { - $build = $this->build->getById($buildID); - $this->build->delete(TABLE_BUILD, $buildID); - die(js::locate($this->createLink('project', 'build', "projectID=$build->project"), 'parent')); - } - } - - /** - * AJAX: get builds of a product in html select. - * - * @param int $productID - * @param string $varName the name of the select object to create - * @param string $build build to selected - * @access public - * @return string - */ - public function ajaxGetProductBuilds($productID, $varName, $build = '') - { - if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'size=4 class=select-3 multiple')); - if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'class=select-3')); - } - - /** - * AJAX: get builds of a project in html select. - * - * @param int $projectID - * @param string $varName the name of the select object to create - * @param string $build build to selected - * @access public - * @return string - */ - public function ajaxGetProjectBuilds($projectID, $productID, $varName, $build = '') - { - if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'size=4 class=select-3 multiple')); - if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'class=select-3')); - } -} + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +class build extends control +{ + /** + * Create a buld. + * + * @param int $projectID + * @access public + * @return void + */ + public function create($projectID) + { + if(!empty($_POST)) + { + $buildID = $this->build->create($projectID); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('build', $buildID, 'opened'); + die(js::locate($this->createLink('project', 'build', "project=$projectID"), 'parent')); + } + + /* Load these models. */ + $this->loadModel('story'); + $this->loadModel('bug'); + $this->loadModel('task'); + $this->loadModel('project'); + $this->loadModel('user'); + + /* Set menu. */ + $this->project->setMenu($this->project->getPairs(), $projectID); + + /* Get stories and bugs. */ + $orderBy = 'status_asc, stage_asc, id_desc'; + $stories = $this->story->getProjectStories($projectID, $orderBy); + $bugs = $this->project->getResolvedBugs($projectID); + + /* Assign. */ + $this->view->header->title = $this->lang->build->create; + $this->view->products = $this->project->getProducts($projectID); + $this->view->projectID = $projectID; + $this->view->users = $this->user->getPairs(); + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->orderBy = $orderBy; + $this->display(); + } + + /** + * Edit a build. + * + * @param int $buildID + * @access public + * @return void + */ + public function edit($buildID) + { + if(!empty($_POST)) + { + $changes = $this->build->update($buildID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('build', $buildID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "buildID=$buildID"), 'parent')); + } + + $this->loadModel('story'); + $this->loadModel('bug'); + $this->loadModel('project'); + + /* Set menu. */ + $build = $this->build->getById((int)$buildID); + $this->project->setMenu($this->project->getPairs(), $build->project); + + /* Get stories and bugs. */ + $orderBy = 'status_asc, stage_asc, id_desc'; + $stories = $this->story->getProjectStories($build->project, $orderBy); + $bugs = $this->project->getResolvedBugs($build->project); + + /* Assign. */ + $this->view->header->title = $this->lang->build->edit; + $this->view->position[] = $this->lang->build->edit; + $this->view->products = $this->project->getProducts($build->project); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->view->build = $build; + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->orderBy = $orderBy; + $this->display(); + } + + /** + * View a build. + * + * @param int $buildID + * @access public + * @return void + */ + public function view($buildID) + { + $this->loadModel('story'); + $this->loadModel('bug'); + + /* Set menu. */ + $build = $this->build->getById((int)$buildID); + if(!$build) die(js::error($this->lang->notFound) . js::locate('back')); + $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($build->stories)->fetchAll(); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($build->bugs)->fetchAll(); + + $this->loadModel('project')->setMenu($this->project->getPairs(), $build->project); + + /* Assign. */ + $this->view->header->title = $this->lang->build->view; + $this->view->position[] = $this->lang->build->view; + $this->view->products = $this->project->getProducts($build->project); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->build = $build; + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->actions = $this->loadModel('action')->getList('build', $buildID); + $this->display(); + } + + /** + * Delete a build. + * + * @param int $buildID + * @param string $confirm yes|noe + * @access public + * @return void + */ + public function delete($buildID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->build->confirmDelete, $this->createLink('build', 'delete', "buildID=$buildID&confirm=yes"))); + } + else + { + $build = $this->build->getById($buildID); + $this->build->delete(TABLE_BUILD, $buildID); + die(js::locate($this->createLink('project', 'build', "projectID=$build->project"), 'parent')); + } + } + + /** + * AJAX: get builds of a product in html select. + * + * @param int $productID + * @param string $varName the name of the select object to create + * @param string $build build to selected + * @access public + * @return string + */ + public function ajaxGetProductBuilds($productID, $varName, $build = '') + { + if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'size=4 class=select-3 multiple')); + if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProductBuildPairs($productID, 'noempty'), $build, 'class=select-3')); + } + + /** + * AJAX: get builds of a project in html select. + * + * @param int $projectID + * @param string $varName the name of the select object to create + * @param string $build build to selected + * @access public + * @return string + */ + public function ajaxGetProjectBuilds($projectID, $productID, $varName, $build = '') + { + if($varName == 'openedBuild') die(html::select($varName . '[]', $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'size=4 class=select-3 multiple')); + if($varName == 'resolvedBuild') die(html::select($varName, $this->build->getProjectBuildPairs($projectID, $productID, 'noempty'), $build, 'class=select-3')); + } +} diff --git a/module/build/lang/en.php b/module/build/lang/en.php index 2ab6393426..9d3e2e3e0e 100644 --- a/module/build/lang/en.php +++ b/module/build/lang/en.php @@ -1,35 +1,35 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->build->common = 'Build'; -$lang->build->create = "Create"; -$lang->build->edit = "Edit"; -$lang->build->delete = "Delete"; -$lang->build->view = "Info"; -$lang->build->ajaxGetProductBuilds = 'API:Product builds'; -$lang->build->ajaxGetProjectBuilds = 'API:Project builds'; - -$lang->build->confirmDelete = "Are sure to delete this build?"; - -$lang->build->id = 'ID'; -$lang->build->product = 'Product'; -$lang->build->project = 'Project'; -$lang->build->name = 'Name'; -$lang->build->date = 'Build date'; -$lang->build->builder = 'Builder'; -$lang->build->scmPath = 'Source code path'; -$lang->build->filePath = 'Package file path'; -$lang->build->desc = 'Desc'; -$lang->build->linkStoriesAndBugs = 'stories and bugs'; -$lang->build->linkStories = 'Stories'; -$lang->build->linkBugs = 'Bugs'; -$lang->build->stories = 'Linked stories'; -$lang->build->bugs = 'Linked bugs'; + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->build->common = 'Build'; +$lang->build->create = "Create"; +$lang->build->edit = "Edit"; +$lang->build->delete = "Delete"; +$lang->build->view = "Info"; +$lang->build->ajaxGetProductBuilds = 'API:Product builds'; +$lang->build->ajaxGetProjectBuilds = 'API:Project builds'; + +$lang->build->confirmDelete = "Are sure to delete this build?"; + +$lang->build->id = 'ID'; +$lang->build->product = 'Product'; +$lang->build->project = 'Project'; +$lang->build->name = 'Name'; +$lang->build->date = 'Build date'; +$lang->build->builder = 'Builder'; +$lang->build->scmPath = 'Source code path'; +$lang->build->filePath = 'Package file path'; +$lang->build->desc = 'Desc'; +$lang->build->linkStoriesAndBugs = 'stories and bugs'; +$lang->build->linkStories = 'Stories'; +$lang->build->linkBugs = 'Bugs'; +$lang->build->stories = 'Linked stories'; +$lang->build->bugs = 'Linked bugs'; diff --git a/module/build/lang/zh-cn.php b/module/build/lang/zh-cn.php index 91e7c9483a..3bda6b1ead 100644 --- a/module/build/lang/zh-cn.php +++ b/module/build/lang/zh-cn.php @@ -1,35 +1,35 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->build->common = 'Build'; -$lang->build->create = "创建Build"; -$lang->build->edit = "编辑Build"; -$lang->build->delete = "删除Build"; -$lang->build->view = "Build详情"; -$lang->build->ajaxGetProductBuilds = '接口:产品Build列表'; -$lang->build->ajaxGetProjectBuilds = '接口:项目Build列表'; - -$lang->build->confirmDelete = "您确认删除该build吗?"; - -$lang->build->id = 'ID'; -$lang->build->product = '产品'; -$lang->build->project = '项目'; -$lang->build->name = '名称编号'; -$lang->build->date = 'Build日期'; -$lang->build->builder = '构建者'; -$lang->build->scmPath = '源代码地址'; -$lang->build->filePath = '存储地址'; -$lang->build->desc = '描述'; -$lang->build->linkStoriesAndBugs = '关联需求和Bug'; -$lang->build->linkStories = '相关需求'; -$lang->build->linkBugs = '相关Bug'; -$lang->build->stories = '已关联需求'; -$lang->build->bugs = '已关联Bug'; + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->build->common = 'Build'; +$lang->build->create = "创建Build"; +$lang->build->edit = "编辑Build"; +$lang->build->delete = "删除Build"; +$lang->build->view = "Build详情"; +$lang->build->ajaxGetProductBuilds = '接口:产品Build列表'; +$lang->build->ajaxGetProjectBuilds = '接口:项目Build列表'; + +$lang->build->confirmDelete = "您确认删除该build吗?"; + +$lang->build->id = 'ID'; +$lang->build->product = '产品'; +$lang->build->project = '项目'; +$lang->build->name = '名称编号'; +$lang->build->date = 'Build日期'; +$lang->build->builder = '构建者'; +$lang->build->scmPath = '源代码地址'; +$lang->build->filePath = '存储地址'; +$lang->build->desc = '描述'; +$lang->build->linkStoriesAndBugs = '关联需求和Bug'; +$lang->build->linkStories = '相关需求'; +$lang->build->linkBugs = '相关Bug'; +$lang->build->stories = '已关联需求'; +$lang->build->bugs = '已关联Bug'; diff --git a/module/build/lang/zh-tw.php b/module/build/lang/zh-tw.php index 15629e8014..ccedf47750 100644 --- a/module/build/lang/zh-tw.php +++ b/module/build/lang/zh-tw.php @@ -1,35 +1,35 @@ - - * @package build - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->build->common = 'Build'; -$lang->build->create = "創建Build"; -$lang->build->edit = "編輯Build"; -$lang->build->delete = "刪除Build"; -$lang->build->view = "Build詳情"; -$lang->build->ajaxGetProductBuilds = '介面:產品Build列表'; -$lang->build->ajaxGetProjectBuilds = '介面:項目Build列表'; - -$lang->build->confirmDelete = "您確認刪除該build嗎?"; - -$lang->build->id = 'ID'; -$lang->build->product = '產品'; -$lang->build->project = '項目'; -$lang->build->name = '名稱編號'; -$lang->build->date = 'Build日期'; -$lang->build->builder = '構建者'; -$lang->build->scmPath = '原始碼地址'; -$lang->build->filePath = '存儲地址'; -$lang->build->desc = '描述'; -$lang->build->linkStoriesAndBugs = '關聯需求和Bug'; -$lang->build->linkStories = '相關需求'; -$lang->build->linkBugs = '相關Bug'; -$lang->build->stories = '已關聯需求'; -$lang->build->bugs = '已關聯Bug'; + + * @package build + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->build->common = 'Build'; +$lang->build->create = "創建Build"; +$lang->build->edit = "編輯Build"; +$lang->build->delete = "刪除Build"; +$lang->build->view = "Build詳情"; +$lang->build->ajaxGetProductBuilds = '介面:產品Build列表'; +$lang->build->ajaxGetProjectBuilds = '介面:項目Build列表'; + +$lang->build->confirmDelete = "您確認刪除該build嗎?"; + +$lang->build->id = 'ID'; +$lang->build->product = '產品'; +$lang->build->project = '項目'; +$lang->build->name = '名稱編號'; +$lang->build->date = 'Build日期'; +$lang->build->builder = '構建者'; +$lang->build->scmPath = '原始碼地址'; +$lang->build->filePath = '存儲地址'; +$lang->build->desc = '描述'; +$lang->build->linkStoriesAndBugs = '關聯需求和Bug'; +$lang->build->linkStories = '相關需求'; +$lang->build->linkBugs = '相關Bug'; +$lang->build->stories = '已關聯需求'; +$lang->build->bugs = '已關聯Bug'; diff --git a/module/build/model.php b/module/build/model.php index 7d16a89d8f..34c57de36a 100644 --- a/module/build/model.php +++ b/module/build/model.php @@ -1,152 +1,152 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->select('t1.*, t2.name as projectName, t3.name as productName') - ->from(TABLE_BUILD)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') - ->where('t1.id')->eq((int)$buildID) - ->orderBy('t1.id DESC') - ->fetch(); - if(!$build) return false; - $build->desc = $this->loadModel('file')->setImgSize($build->desc); - return $build; - } - - /** - * Get builds of a project. - * - * @param int $projectID - * @access public - * @return array - */ - public function getProjectBuilds($projectID) - { - return $this->dao->select('t1.*, t2.name as projectName, t3.name as productName') - ->from(TABLE_BUILD)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy('t1.date DESC, t1.id desc') - ->fetchAll(); - } - - /** - * Get builds of a project in pairs. - * - * @param int $projectID - * @param int $productID - * @param string $params noempty|notrunk, can be a set of them - * @access public - * @return array - */ - public function getProjectBuildPairs($projectID, $productID, $params = '') - { - $sysBuilds = array(); - if(strpos($params, 'noempty') === false) $sysBuilds = array('' => ''); - if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk'); - - $builds = $this->dao->select('id,name')->from(TABLE_BUILD) - ->where('project')->eq((int)$projectID) - ->beginIF($productID)->andWhere('product')->eq((int)$productID)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy('date desc, id desc')->fetchPairs(); - if(!$builds) return $sysBuilds; - $releases = $this->dao->select('build,name')->from(TABLE_RELEASE) - ->where('build')->in(array_keys($builds)) - ->andWhere('deleted')->eq(0) - ->fetchPairs(); - foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName; - return $sysBuilds + $builds; - } - - /** - * Get builds of a product in pairs. - * - * @param int $productID - * @param string $params noempty|notrunk, can be a set of them - * @access public - * @return string - */ - public function getProductBuildPairs($productID, $params = '') - { - $sysBuilds = array(); - if(strpos($params, 'noempty') === false) $sysBuilds = array('' => ''); - if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk'); - - $builds = $this->dao->select('id,name')->from(TABLE_BUILD) - ->where('product')->eq((int)$productID) - ->andWhere('deleted')->eq(0) - ->orderBy('date desc, id desc')->fetchPairs(); - if(!$builds) return $sysBuilds; - return $sysBuilds + $builds; - } - - /** - * Create a build - * - * @param int $projectID - * @access public - * @return void - */ - public function create($projectID) - { - $build->stories = ''; - $build->bugs = ''; - - $build = fixer::input('post')->stripTags('name') - ->join('stories', ',') - ->join('bugs', ',') - ->add('project', (int)$projectID)->get(); - $this->dao->insert(TABLE_BUILD)->data($build)->autoCheck()->batchCheck($this->config->build->create->requiredFields, 'notempty')->check('name','unique')->exec(); - if(!dao::isError()) return $this->dao->lastInsertID(); - } - - /** - * Update a build. - * - * @param int $buildID - * @access public - * @return void - */ - public function update($buildID) - { - $oldBuild = $this->getByID($buildID); - $build = fixer::input('post') - ->stripTags('name') - ->setDefault('stories', '') - ->setDefault('bugs', '') - ->join('stories', ',') - ->join('bugs', ',') - ->get(); - $this->dao->update(TABLE_BUILD)->data($build) - ->autoCheck() - ->batchCheck($this->config->build->edit->requiredFields, 'notempty') - ->where('id')->eq((int)$buildID) - ->check('name','unique', "id != $buildID") - ->exec(); - if(!dao::isError()) return common::createChanges($oldBuild, $build); - } -} + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->select('t1.*, t2.name as projectName, t3.name as productName') + ->from(TABLE_BUILD)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.id')->eq((int)$buildID) + ->orderBy('t1.id DESC') + ->fetch(); + if(!$build) return false; + $build->desc = $this->loadModel('file')->setImgSize($build->desc); + return $build; + } + + /** + * Get builds of a project. + * + * @param int $projectID + * @access public + * @return array + */ + public function getProjectBuilds($projectID) + { + return $this->dao->select('t1.*, t2.name as projectName, t3.name as productName') + ->from(TABLE_BUILD)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('t1.date DESC, t1.id desc') + ->fetchAll(); + } + + /** + * Get builds of a project in pairs. + * + * @param int $projectID + * @param int $productID + * @param string $params noempty|notrunk, can be a set of them + * @access public + * @return array + */ + public function getProjectBuildPairs($projectID, $productID, $params = '') + { + $sysBuilds = array(); + if(strpos($params, 'noempty') === false) $sysBuilds = array('' => ''); + if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk'); + + $builds = $this->dao->select('id,name')->from(TABLE_BUILD) + ->where('project')->eq((int)$projectID) + ->beginIF($productID)->andWhere('product')->eq((int)$productID)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy('date desc, id desc')->fetchPairs(); + if(!$builds) return $sysBuilds; + $releases = $this->dao->select('build,name')->from(TABLE_RELEASE) + ->where('build')->in(array_keys($builds)) + ->andWhere('deleted')->eq(0) + ->fetchPairs(); + foreach($releases as $buildID => $releaseName) $builds[$buildID] = $releaseName; + return $sysBuilds + $builds; + } + + /** + * Get builds of a product in pairs. + * + * @param int $productID + * @param string $params noempty|notrunk, can be a set of them + * @access public + * @return string + */ + public function getProductBuildPairs($productID, $params = '') + { + $sysBuilds = array(); + if(strpos($params, 'noempty') === false) $sysBuilds = array('' => ''); + if(strpos($params, 'notrunk') === false) $sysBuilds = $sysBuilds + array('trunk' => 'Trunk'); + + $builds = $this->dao->select('id,name')->from(TABLE_BUILD) + ->where('product')->eq((int)$productID) + ->andWhere('deleted')->eq(0) + ->orderBy('date desc, id desc')->fetchPairs(); + if(!$builds) return $sysBuilds; + return $sysBuilds + $builds; + } + + /** + * Create a build + * + * @param int $projectID + * @access public + * @return void + */ + public function create($projectID) + { + $build->stories = ''; + $build->bugs = ''; + + $build = fixer::input('post')->stripTags('name') + ->join('stories', ',') + ->join('bugs', ',') + ->add('project', (int)$projectID)->get(); + $this->dao->insert(TABLE_BUILD)->data($build)->autoCheck()->batchCheck($this->config->build->create->requiredFields, 'notempty')->check('name','unique')->exec(); + if(!dao::isError()) return $this->dao->lastInsertID(); + } + + /** + * Update a build. + * + * @param int $buildID + * @access public + * @return void + */ + public function update($buildID) + { + $oldBuild = $this->getByID($buildID); + $build = fixer::input('post') + ->stripTags('name') + ->setDefault('stories', '') + ->setDefault('bugs', '') + ->join('stories', ',') + ->join('bugs', ',') + ->get(); + $this->dao->update(TABLE_BUILD)->data($build) + ->autoCheck() + ->batchCheck($this->config->build->edit->requiredFields, 'notempty') + ->where('id')->eq((int)$buildID) + ->check('name','unique', "id != $buildID") + ->exec(); + if(!dao::isError()) return common::createChanges($oldBuild, $build); + } +} diff --git a/module/build/view/create.html.php b/module/build/view/create.html.php index 7b07a201a7..dd3735b632 100644 --- a/module/build/view/create.html.php +++ b/module/build/view/create.html.php @@ -1,97 +1,97 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
build->create;?>
build->product;?>
build->name;?>
build->builder;?>user->account, 'class="select-3"');?>
build->date;?>
build->scmPath;?>
build->filePath;?>
build->linkStoriesAndBugs;?> -
- - -
-
build->desc;?>
-
- + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->create;?>
build->product;?>
build->name;?>
build->builder;?>user->account, 'class="select-3"');?>
build->date;?>
build->scmPath;?>
build->filePath;?>
build->linkStoriesAndBugs;?> +
+ + +
+
build->desc;?>
+
+ diff --git a/module/build/view/edit.html.php b/module/build/view/edit.html.php index 07e35e236e..29ecdc9df4 100644 --- a/module/build/view/edit.html.php +++ b/module/build/view/edit.html.php @@ -1,97 +1,97 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
build->edit;?>
build->product;?>product, "class='select-3'");?>
build->name;?>name, "class='text-3'");?>
build->builder;?>builder, 'class="select-3"');?>
build->date;?>date, "class='text-3 date'");?>
build->scmPath;?>scmPath, "class='text-1'");?>
build->filePath;?>filePath, "class='text-1'");?>
build->linkStoriesAndBugs;?> -
- - -
-
build->desc;?>desc), "rows='15' class='area-1'");?>
project);?>
-
- + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->edit;?>
build->product;?>product, "class='select-3'");?>
build->name;?>name, "class='text-3'");?>
build->builder;?>builder, 'class="select-3"');?>
build->date;?>date, "class='text-3 date'");?>
build->scmPath;?>scmPath, "class='text-1'");?>
build->filePath;?>filePath, "class='text-1'");?>
build->linkStoriesAndBugs;?> +
+ + +
+
build->desc;?>desc), "rows='15' class='area-1'");?>
project);?>
+
+ diff --git a/module/build/view/view.html.php b/module/build/view/view.html.php index 655d30cfc5..268ca0fc0e 100644 --- a/module/build/view/view.html.php +++ b/module/build/view/view.html.php @@ -1,117 +1,117 @@ - - * @package build - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
build->view;?>
build->product;?>productName;?>
build->name;?>'>name;?>
build->builder;?>builder];?>
build->date;?>date;?>
build->scmPath;?>scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>
build->filePath;?>filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>
build->stories;?> -
- - - - - - - - - - - $story):?> - createLink('story', 'view', "storyID=$story->id");?> - - - - - - - - - - -
idAB;?>priAB;?>story->title;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>
id);?>story->priList[$story->pri];?>title, '', "class='preview'");?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
-
-
build->bugs;?> -
- - - - - - - - - - - - createLink('bug', 'view', "bugID=$bug->id");?> - - - - - - - - - - -
idAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?>
id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>openedBy];?>openedDate, 5, 11)?>resolvedBy];?>resolvedDate, 5, 11)?>
-
-
build->desc;?>desc;?>
-
- session->buildList ? $this->session->buildList : $this->createLink('project', 'build', "projectID=$build->project"); - if(!$build->deleted) - { - common::printLink('build', 'edit', "buildID=$build->id", $lang->edit); - common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
- - + + * @package build + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
build->view;?>
build->product;?>productName;?>
build->name;?>'>name;?>
build->builder;?>builder];?>
build->date;?>date;?>
build->scmPath;?>scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>
build->filePath;?>filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>
build->stories;?> +
+ + + + + + + + + + + $story):?> + createLink('story', 'view', "storyID=$story->id");?> + + + + + + + + + + +
idAB;?>priAB;?>story->title;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>
id);?>story->priList[$story->pri];?>title, '', "class='preview'");?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
+
+
build->bugs;?> +
+ + + + + + + + + + + + createLink('bug', 'view', "bugID=$bug->id");?> + + + + + + + + + + +
idAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?>
id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>openedBy];?>openedDate, 5, 11)?>resolvedBy];?>resolvedDate, 5, 11)?>
+
+
build->desc;?>desc;?>
+
+ session->buildList ? $this->session->buildList : $this->createLink('project', 'build', "projectID=$build->project"); + if(!$build->deleted) + { + common::printLink('build', 'edit', "buildID=$build->id", $lang->edit); + common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
+ + diff --git a/module/common/control.php b/module/common/control.php index be741fbee2..b7a8d6cf9a 100644 --- a/module/common/control.php +++ b/module/common/control.php @@ -1,265 +1,265 @@ - - * @package common - * @version $Id$ - * @link http://www.zentao.net - */ -class common extends control -{ - /** - * The construc method, to do some auto things. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->common->startSession(); - $this->common->sendHeader(); - $this->common->setCompany(); - $this->common->setUser(); - $this->app->loadLang('company'); - } - - /** - * Check the user has permission to access this method, if not, locate to the login page or deny page. - * - * @access public - * @return void - */ - public function checkPriv() - { - $module = $this->app->getModuleName(); - $method = $this->app->getMethodName(); - if($this->common->isOpenMethod($module, $method)) return true; - if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth(); - if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie(); - - if(isset($this->app->user)) - { - if(!common::hasPriv($module, $method)) $this->common->deny($module, $method); - } - else - { - $referer = helper::safe64Encode($this->app->getURI(true)); - $this->locate($this->createLink('user', 'login', "referer=$referer")); - } - } - - /** - * Check upgrade's status file is ok or not. - * - * @access public - * @return void - */ - public function checkUpgradeStatus() - { - $statusFile = $this->app->getAppRoot() . 'www' . $this->pathFix . 'ok'; - if(!file_exists($statusFile) or time() - filemtime($statusFile) > 3600) - { - $this->app->loadLang('upgrade'); - echo ""; - echo "
"; - printf($this->lang->upgrade->setStatusFile, $statusFile, $statusFile, $statusFile); - die('
'); - } - } - - /** - * Check the user has permisson of one method of one module. - * - * @param string $module - * @param string $method - * @static - * @access public - * @return bool - */ - public static function hasPriv($module, $method) - { - global $app; - - /* Check is the super admin or not. */ - $account = ',' . $app->user->account . ','; - if(strpos($app->company->admins, $account) !== false) return true; - - /* If not super admin, check the rights. */ - $rights = $app->user->rights; - if(isset($rights[strtolower($module)][strtolower($method)])) return true; - return false; - } - - /** - * Replace the %s of one key of a menu by $params. - * - * All the menus are defined in the common's language file. But there're many dynamic params, so in the defination, - * we used %s as placeholder. These %s should be setted in one module. - * - * The items of one module's menu may be an string or array. For example, please see module/common/lang. - * - * @param string $object the menus of one module - * @param string $key the menu item to be replaced - * @param string $params the params passed to the menu item - * @access public - * @return void - */ - public function setMenuVars($menu, $key, $params) - { - if(is_array($params)) - { - if(is_array($menu->$key)) - { - $menu->$key = (object)$menu->$key; - $menu->$key->link = vsprintf($menu->$key->link, $params); - $menu->$key = (array)$menu->$key; - } - else - { - $menu->$key = vsprintf($menu->$key, $params); - } - } - else - { - if(is_array($menu->$key)) - { - $menu->$key = (object)$menu->$key; - $menu->$key->link = sprintf($menu->$key->link, $params); - $menu->$key = (array)$menu->$key; - } - else - { - $menu->$key = sprintf($menu->$key, $params); - } - } - } - - /** - * Print the link contains orderBy field. - * - * This method will auto set the orderby param according the params. Fox example, if the order by is desc, - * will be changed to asc. - * - * @param string $fieldName the field name to sort by - * @param string $orderBy the order by string - * @param string $vars the vars to be passed - * @param string $label the label of the link - * @param string $module the module name - * @param string $method the method name - * @static - * @access public - * @return void - */ - public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '') - { - global $lang, $app; - if(empty($module)) $module= $app->getModuleName(); - if(empty($method)) $method= $app->getMethodName(); - $className = 'header'; - - if(strpos($orderBy, $fieldName) !== false) - { - if(stripos($orderBy, 'desc') !== false) - { - $orderBy = str_ireplace('desc', 'asc', $orderBy); - $className = 'headerSortUp'; - } - elseif(stripos($orderBy, 'asc') !== false) - { - $orderBy = str_ireplace('asc', 'desc', $orderBy); - $className = 'headerSortDown'; - } - } - else - { - $orderBy = $fieldName . '_' . 'asc'; - $className = 'header'; - } - $link = helper::createLink($module, $method, sprintf($vars, $orderBy)); - echo "
" . html::a($link, $label) . '
'; - } - - /** - * Print link to an modules' methd. - * - * Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true. - * - * @param string $module the module name - * @param string $method the method - * @param string $vars vars to be passed - * @param string $label the label of the link - * @param string $target the target of the link - * @param string $misc others - * @static - * @access public - * @return bool - */ - public static function printLink($module, $method, $vars = '', $label, $target = '', $misc = '') - { - if(!common::hasPriv($module, $method)) return false; - echo html::a(helper::createLink($module, $method, $vars), $label, $target, $misc); - return true; - } - - /** - * Create changes of one object. - * - * @param mixed $old the old object - * @param mixed $new the new object - * @static - * @access public - * @return array - */ - public static function createChanges($old, $new) - { - global $config; - $changes = array(); - $magicQuote = get_magic_quotes_gpc(); - foreach($new as $key => $value) - { - if(strtolower($key) == 'lastediteddate') continue; - if(strtolower($key) == 'lasteditedby') continue; - if(strtolower($key) == 'assigneddate') continue; - if(strtolower($key) == 'editedby') continue; - if(strtolower($key) == 'editeddate') continue; - - if($magicQuote) $value = stripslashes($value); - if($value != $old->$key) - { - $diff = ''; - if(substr_count($value, "\n") > 1 or substr_count($old->$key, "\n") > 1 or strpos('name,title,desc,spec,steps,content,digest', strtolower($key)) !== false) $diff = commonModel::diff($old->$key, $value); - $changes[] = array('field' => $key, 'old' => $old->$key, 'new' => $value, 'diff' => $diff); - } - } - return $changes; - } - - /** - * Get the full url of the system. - * - * @access public - * @return string - */ - public function getSysURL() - { - $httpType = isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ? 'https' : 'http'; - $httpHost = $_SERVER['HTTP_HOST']; - return "$httpType://$httpHost"; - } - - /** - * Print the run info. - * - * @param mixed $startTime the start time. - * @access public - * @return void - */ - public function printRunInfo($startTime) - { - vprintf($this->lang->runInfo, $this->common->getRunInfo($startTime)); - } -} + + * @package common + * @version $Id$ + * @link http://www.zentao.net + */ +class common extends control +{ + /** + * The construc method, to do some auto things. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->common->startSession(); + $this->common->sendHeader(); + $this->common->setCompany(); + $this->common->setUser(); + $this->app->loadLang('company'); + } + + /** + * Check the user has permission to access this method, if not, locate to the login page or deny page. + * + * @access public + * @return void + */ + public function checkPriv() + { + $module = $this->app->getModuleName(); + $method = $this->app->getMethodName(); + if($this->common->isOpenMethod($module, $method)) return true; + if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth(); + if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie(); + + if(isset($this->app->user)) + { + if(!common::hasPriv($module, $method)) $this->common->deny($module, $method); + } + else + { + $referer = helper::safe64Encode($this->app->getURI(true)); + $this->locate($this->createLink('user', 'login', "referer=$referer")); + } + } + + /** + * Check upgrade's status file is ok or not. + * + * @access public + * @return void + */ + public function checkUpgradeStatus() + { + $statusFile = $this->app->getAppRoot() . 'www' . $this->pathFix . 'ok'; + if(!file_exists($statusFile) or time() - filemtime($statusFile) > 3600) + { + $this->app->loadLang('upgrade'); + echo ""; + echo "
"; + printf($this->lang->upgrade->setStatusFile, $statusFile, $statusFile, $statusFile); + die('
'); + } + } + + /** + * Check the user has permisson of one method of one module. + * + * @param string $module + * @param string $method + * @static + * @access public + * @return bool + */ + public static function hasPriv($module, $method) + { + global $app; + + /* Check is the super admin or not. */ + $account = ',' . $app->user->account . ','; + if(strpos($app->company->admins, $account) !== false) return true; + + /* If not super admin, check the rights. */ + $rights = $app->user->rights; + if(isset($rights[strtolower($module)][strtolower($method)])) return true; + return false; + } + + /** + * Replace the %s of one key of a menu by $params. + * + * All the menus are defined in the common's language file. But there're many dynamic params, so in the defination, + * we used %s as placeholder. These %s should be setted in one module. + * + * The items of one module's menu may be an string or array. For example, please see module/common/lang. + * + * @param string $object the menus of one module + * @param string $key the menu item to be replaced + * @param string $params the params passed to the menu item + * @access public + * @return void + */ + public function setMenuVars($menu, $key, $params) + { + if(is_array($params)) + { + if(is_array($menu->$key)) + { + $menu->$key = (object)$menu->$key; + $menu->$key->link = vsprintf($menu->$key->link, $params); + $menu->$key = (array)$menu->$key; + } + else + { + $menu->$key = vsprintf($menu->$key, $params); + } + } + else + { + if(is_array($menu->$key)) + { + $menu->$key = (object)$menu->$key; + $menu->$key->link = sprintf($menu->$key->link, $params); + $menu->$key = (array)$menu->$key; + } + else + { + $menu->$key = sprintf($menu->$key, $params); + } + } + } + + /** + * Print the link contains orderBy field. + * + * This method will auto set the orderby param according the params. Fox example, if the order by is desc, + * will be changed to asc. + * + * @param string $fieldName the field name to sort by + * @param string $orderBy the order by string + * @param string $vars the vars to be passed + * @param string $label the label of the link + * @param string $module the module name + * @param string $method the method name + * @static + * @access public + * @return void + */ + public static function printOrderLink($fieldName, $orderBy, $vars, $label, $module = '', $method = '') + { + global $lang, $app; + if(empty($module)) $module= $app->getModuleName(); + if(empty($method)) $method= $app->getMethodName(); + $className = 'header'; + + if(strpos($orderBy, $fieldName) !== false) + { + if(stripos($orderBy, 'desc') !== false) + { + $orderBy = str_ireplace('desc', 'asc', $orderBy); + $className = 'headerSortUp'; + } + elseif(stripos($orderBy, 'asc') !== false) + { + $orderBy = str_ireplace('asc', 'desc', $orderBy); + $className = 'headerSortDown'; + } + } + else + { + $orderBy = $fieldName . '_' . 'asc'; + $className = 'header'; + } + $link = helper::createLink($module, $method, sprintf($vars, $orderBy)); + echo "
" . html::a($link, $label) . '
'; + } + + /** + * Print link to an modules' methd. + * + * Before printing, check the privilege first. If no privilege, return fasle. Else, print the link, return true. + * + * @param string $module the module name + * @param string $method the method + * @param string $vars vars to be passed + * @param string $label the label of the link + * @param string $target the target of the link + * @param string $misc others + * @static + * @access public + * @return bool + */ + public static function printLink($module, $method, $vars = '', $label, $target = '', $misc = '') + { + if(!common::hasPriv($module, $method)) return false; + echo html::a(helper::createLink($module, $method, $vars), $label, $target, $misc); + return true; + } + + /** + * Create changes of one object. + * + * @param mixed $old the old object + * @param mixed $new the new object + * @static + * @access public + * @return array + */ + public static function createChanges($old, $new) + { + global $config; + $changes = array(); + $magicQuote = get_magic_quotes_gpc(); + foreach($new as $key => $value) + { + if(strtolower($key) == 'lastediteddate') continue; + if(strtolower($key) == 'lasteditedby') continue; + if(strtolower($key) == 'assigneddate') continue; + if(strtolower($key) == 'editedby') continue; + if(strtolower($key) == 'editeddate') continue; + + if($magicQuote) $value = stripslashes($value); + if($value != $old->$key) + { + $diff = ''; + if(substr_count($value, "\n") > 1 or substr_count($old->$key, "\n") > 1 or strpos('name,title,desc,spec,steps,content,digest', strtolower($key)) !== false) $diff = commonModel::diff($old->$key, $value); + $changes[] = array('field' => $key, 'old' => $old->$key, 'new' => $value, 'diff' => $diff); + } + } + return $changes; + } + + /** + * Get the full url of the system. + * + * @access public + * @return string + */ + public function getSysURL() + { + $httpType = isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' ? 'https' : 'http'; + $httpHost = $_SERVER['HTTP_HOST']; + return "$httpType://$httpHost"; + } + + /** + * Print the run info. + * + * @param mixed $startTime the start time. + * @access public + * @return void + */ + public function printRunInfo($startTime) + { + vprintf($this->lang->runInfo, $this->common->getRunInfo($startTime)); + } +} diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 97774bd894..c34406b0f1 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -1,300 +1,300 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->arrow = ' » '; -$lang->colon = '::'; -$lang->comma = ','; -$lang->dot = '.'; -$lang->at = ' at '; -$lang->downArrow = '↓'; - -$lang->ZenTaoPMS = 'ZenTaoPMS'; -$lang->welcome = "Welcome to『%s』{$lang->colon} {$lang->ZenTaoPMS}"; -$lang->myControl = "Dashboard"; -$lang->currentPos = 'Current'; -$lang->logout = 'Logout'; -$lang->login = 'Login'; -$lang->aboutZenTao = 'About'; -$lang->todayIs = '%s, '; -$lang->runInfo = "
Time: %s ms, Memory: %s KB, Queries: %s.
"; - -$lang->reset = 'Reset'; -$lang->edit = 'Edit'; -$lang->copy = 'Copy'; -$lang->delete = 'Delete'; -$lang->close = 'Close'; -$lang->link = 'Link'; -$lang->unlink = 'Unlink'; -$lang->import = 'Import'; -$lang->export = 'Export'; -$lang->setFileName = 'Filename:'; -$lang->activate = 'Activate'; -$lang->submitting = 'Saving...'; -$lang->save = 'Save'; -$lang->confirm = 'Confirm'; -$lang->preview = 'View'; -$lang->goback = 'Back'; -$lang->go = 'GO'; -$lang->more = 'More'; - -$lang->actions = 'Actions'; -$lang->comment = 'Comment'; -$lang->history = 'History'; -$lang->attatch = 'Attatch'; -$lang->reverse = '[Reverse]'; -$lang->switchDisplay= '[Toggle Show]'; -$lang->switchHelp = 'Toggle Help'; -$lang->addFiles = 'Add Files'; -$lang->files = 'Files '; -$lang->unfold = '+'; -$lang->fold = '-'; - -$lang->selectAll = 'Select All'; -$lang->notFound = 'Sorry, the object not found.'; -$lang->showAll = '++ Show All ++'; -$lang->hideClosed = '-- Hide Closed--'; - -$lang->future = 'Future'; -$lang->year = 'Year'; -$lang->workingHour = 'Hour'; - -$lang->idAB = 'ID'; -$lang->priAB = 'P'; -$lang->statusAB = 'Status'; -$lang->openedByAB = 'Open'; -$lang->assignedToAB = 'To'; -$lang->typeAB = 'Type'; - -$lang->common->common = 'Common module'; - -/* The main menu. */ -$lang->menu->my = 'Dashboard|my|index'; -$lang->menu->product = 'Product|product|index'; -$lang->menu->project = 'Project|project|index'; -$lang->menu->qa = 'Test|qa|index'; -$lang->menu->doc = 'Doc|doc|index'; -$lang->menu->company = 'Company|company|index'; -$lang->menu->admin = 'Admin|admin|index'; - -/* The objects in the search box. */ -$lang->searchObjects['bug'] = 'Bug'; -$lang->searchObjects['story'] = 'Story'; -$lang->searchObjects['task'] = 'Task'; -$lang->searchObjects['testcase'] = 'Test Case'; -$lang->searchObjects['project'] = 'Project'; -$lang->searchObjects['product'] = 'Product'; -$lang->searchObjects['user'] = 'User'; -$lang->searchObjects['build'] = 'Build'; -$lang->searchObjects['release'] = 'Release'; -$lang->searchObjects['productplan'] = 'Plan'; -$lang->searchObjects['testtask'] = 'Test Task'; -$lang->searchObjects['doc'] = 'Doc'; -$lang->searchTips = 'Id here'; - -/* File type of export. */ -$lang->exportFileTypeList['csv'] = 'csv'; -$lang->exportFileTypeList['xml'] = 'xml'; -$lang->exportFileTypeList['html'] = 'html'; - -/* Themes. */ -$lang->themes['default'] = 'Default'; -$lang->themes['green'] = 'Green'; -$lang->themes['red'] = 'Red'; -$lang->themes['classblue'] = 'Blue'; - -/* Index mododule menu. */ -$lang->index->menu->product = 'Products|product|browse'; -$lang->index->menu->project = 'Projects|project|browse'; - -/* Dashboard menu. */ -$lang->my->menu->account = '%s' . $lang->arrow; -$lang->my->menu->index = 'Index|my|index'; -$lang->my->menu->todo = array('link' => 'Todo|my|todo|', 'subModule' => 'todo'); -$lang->my->menu->task = 'Task|my|task|'; -$lang->my->menu->bug = 'Bug|my|bug|'; -$lang->my->menu->testtask = 'Test|my|testtask|'; -$lang->my->menu->story = 'Story|my|story|'; -$lang->my->menu->myProject = 'Project|my|project|'; -$lang->my->menu->dynamic = 'Dynamic|my|dynamic|'; -$lang->my->menu->profile = array('link' => 'Profile|my|profile|', 'alias' => 'editprofile'); -$lang->todo->menu = $lang->my->menu; - -/* Product menu. */ -$lang->product->menu->list = '%s'; -$lang->product->menu->story = array('link' => 'Story|product|browse|productID=%s', 'subModule' => 'story'); -$lang->product->menu->dynamic = 'Dynamic|product|dynamic|productID=%s'; -$lang->product->menu->plan = array('link' => 'Plan|productplan|browse|productID=%s', 'subModule' => 'productplan'); -$lang->product->menu->release = array('link' => 'Release|release|browse|productID=%s', 'subModule' => 'release'); -$lang->product->menu->roadmap = 'Roadmap|product|roadmap|productID=%s'; -$lang->product->menu->doc = array('link' => 'Doc|product|doc|productID=%s', 'subModule' => 'doc'); -$lang->product->menu->view = 'Info|product|view|productID=%s'; -$lang->product->menu->edit = 'Edit|product|edit|productID=%s'; -$lang->product->menu->delete = array('link' => 'Delete|product|delete|productID=%s', 'target' => 'hiddenwin'); -$lang->product->menu->module = 'Modules|tree|browse|productID=%s&view=story'; -$lang->product->menu->order = 'Order|product|order|productID=%s'; -$lang->product->menu->create = array('link' => 'New Product|product|create', 'float' => 'right'); -$lang->product->menu->project = array('link' => 'Project list|product|project|status=all&productID=%s', 'float' => 'right'); -$lang->product->menu->all = array('link' => 'All product|product|index|locate=false', 'float' => 'right'); -$lang->story->menu = $lang->product->menu; -$lang->productplan->menu = $lang->product->menu; -$lang->release->menu = $lang->product->menu; - -/* Project menu. */ -$lang->project->menu->list = '%s'; -$lang->project->menu->task = array('link' => 'Task|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); -$lang->project->menu->story = array('link' => 'Story|project|story|projectID=%s'); -$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; -$lang->project->menu->dynamic = 'Dynamic|project|dynamic|projectID=%s'; -$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); -$lang->project->menu->testtask = 'Testtask|project|testtask|projectID=%s'; -$lang->project->menu->burn = 'Burn|project|burn|projectID=%s'; -$lang->project->menu->team = array('link' => 'Team|project|team|projectID=%s', 'alias' => 'managemembers'); -$lang->project->menu->doc = array('link' => 'Doc|project|doc|porjectID=%s', 'subModule' => 'doc'); -$lang->project->menu->product = 'Link Product|project|manageproducts|projectID=%s'; -$lang->project->menu->linkstory = array('link' => 'Link Story|project|linkstory|projectID=%s'); -$lang->project->menu->view = 'Info|project|view|projectID=%s'; -$lang->project->menu->edit = 'Edit|project|edit|projectID=%s'; -$lang->project->menu->delete = array('link' => 'Delete|project|delete|projectID=%s', 'target' => 'hiddenwin'); -$lang->project->menu->order = 'Order|project|order|projectID=%s'; -$lang->project->menu->create = array('link' => 'New Project|project|create', 'float' => 'right'); -$lang->project->menu->toCopy = array('link' => 'Copy Project|project|create|projectID=©ProjectID=%s', 'float' => 'right'); -$lang->project->menu->all = array('link' => 'Project list|project|index|locate=no', 'float' => 'right'); -$lang->task->menu = $lang->project->menu; -$lang->build->menu = $lang->project->menu; - -/* QA menu. */ -$lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); -$lang->bug->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); -$lang->bug->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s'); - -$lang->testcase->menu->product = '%s'; -$lang->testcase->menu->bug = array('link' => 'Bug|bug|browse|productID=%s'); -$lang->testcase->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); -$lang->testcase->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s'); - -$lang->testtask->menu->product = '%s'; -$lang->testtask->menu->bug = array('link' => 'Bug|bug|browse|productID=%s'); -$lang->testtask->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s'); -$lang->testtask->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); - -/* Doc menu. */ -$lang->doc->menu->list = '%s'; -$lang->doc->menu->browse = array('link' => 'Doc|doc|browse|libID=%s'); -$lang->doc->menu->edit = 'Edit Library|doc|editLib|libID=%s'; -$lang->doc->menu->module = 'Modules|tree|browse|libID=%s&viewType=doc'; -$lang->doc->menu->delete = array('link' => 'Delete Library|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); -$lang->doc->menu->create = array('link' => 'New Library|doc|createLib', 'float' => 'right'); - -/* Company menu. */ -$lang->company->menu->name = '%s' . $lang->arrow; -$lang->company->menu->browseUser = array('link' => 'Users|company|browse', 'subModule' => 'user'); -$lang->company->menu->dept = array('link' => 'Department|dept|browse', 'subModule' => 'dept'); -$lang->company->menu->browseGroup = array('link' => 'Group|group|browse', 'subModule' => 'group'); -$lang->company->menu->edit = array('link' => 'Company|company|edit'); -$lang->company->menu->dynamic = 'Dynamic|company|dynamic|'; -$lang->company->menu->addGroup = array('link' => 'Add Group|group|create', 'float' => 'right'); -$lang->company->menu->addUser = array('link' => 'Add User|user|create|dept=%s&from=company', 'subModule' => 'user', 'float' => 'right'); -$lang->dept->menu = $lang->company->menu; -$lang->group->menu = $lang->company->menu; - -/* User menu. */ -$lang->user->menu->account = '%s' . $lang->arrow; -$lang->user->menu->todo = array('link' => 'Todo|user|todo|account=%s', 'subModule' => 'todo'); -$lang->user->menu->task = 'Task|user|task|account=%s'; -$lang->user->menu->bug = 'Bug|user|bug|account=%s'; -$lang->user->menu->dynamic = 'Dynamic|user|dynamic|type=today&account=%s'; -$lang->user->menu->projectList = 'Project|user|project|account=%s'; -$lang->user->menu->profile = array('link' => 'Profile|user|profile|account=%s', 'alias' => 'edit'); -$lang->user->menu->browse = array('link' => 'Manage user|company|browse|', 'float' => 'right'); - -/* Admin menu. */ -$lang->admin->menu->index = array('link' => 'Index|admin|index', 'subModule' => 'admin'); -$lang->admin->menu->extension = array('link' => 'Extension|extension|browse', 'subModule' => 'extension'); -$lang->admin->menu->editor = array('link' => 'Extension editor|editor|index', 'subModule' => 'editor'); -$lang->admin->menu->mail = array('link' => 'ConfigEmail|mail|set', 'subModule' => 'mail'); -$lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert'); -$lang->admin->menu->trashes = array('link' => 'Trash|action|trash', 'subModule' => 'action'); -$lang->convert->menu = $lang->admin->menu; -$lang->upgrade->menu = $lang->admin->menu; -$lang->action->menu = $lang->admin->menu; -$lang->extension->menu = $lang->admin->menu; -$lang->editor->menu = $lang->admin->menu; -$lang->mail->menu = $lang->admin->menu; - -/* Groups. */ -$lang->menugroup->release = 'product'; -$lang->menugroup->story = 'product'; -$lang->menugroup->productplan = 'product'; -$lang->menugroup->task = 'project'; -$lang->menugroup->build = 'project'; -$lang->menugroup->convert = 'admin'; -$lang->menugroup->upgrade = 'admin'; -$lang->menugroup->user = 'company'; -$lang->menugroup->group = 'company'; -$lang->menugroup->bug = 'qa'; -$lang->menugroup->testcase = 'qa'; -$lang->menugroup->testtask = 'qa'; -$lang->menugroup->people = 'company'; -$lang->menugroup->dept = 'company'; -$lang->menugroup->todo = 'my'; -$lang->menugroup->action = 'admin'; -$lang->menugroup->extension = 'admin'; -$lang->menugroup->editor = 'admin'; -$lang->menugroup->mail = 'admin'; - -/* Error info. */ -$lang->error->companyNotFound = "The domain %s does not exist."; -$lang->error->length = array("『%s』length should be『%s』", "『%s』length should between『%s』and 『%s』."); -$lang->error->reg = "『%s』should like『%s』"; -$lang->error->unique = "『%s』has『%s』already."; -$lang->error->gt = "『%s』must great than『%s』."; -$lang->error->notempty = "『%s』can not be empty."; -$lang->error->empty = "『%s』 must be empty."; -$lang->error->equal = "『%s』must be『%s』."; -$lang->error->int = array("『%s』should be interger", "『%s』should between『%s-%s』."); -$lang->error->float = "『%s』should be a interger or float."; -$lang->error->email = "『%s』should be email."; -$lang->error->date = "『%s』should be date"; -$lang->error->account = "『%s』should be a valid account."; -$lang->error->passwordsame = "Two passwords must be the same"; -$lang->error->passwordrule = "Password should more than six letters."; -$lang->error->accessDenied = 'No purview'; - -/* Pager. */ -$lang->pager->noRecord = "No records yet."; -$lang->pager->digest = "%s records, %s per page, %s/%s "; -$lang->pager->first = "First"; -$lang->pager->pre = "Previous"; -$lang->pager->next = "Next"; -$lang->pager->last = "Last"; -$lang->pager->locate = "GO!"; - -$lang->zentaoSite = "Official Site"; -$lang->chinaScrum = "Scrum community "; -$lang->agileTraining = "Training "; -$lang->donate = "Donate "; -$lang->zentaoKeywords = "Open Source Project Management System"; -$lang->zentaoDESC = "ZenTaoPMS is an open sourced project management system."; - - - -/* Date times. */ -define('DT_DATETIME1', 'Y-m-d H:i:s'); -define('DT_DATETIME2', 'y-m-d H:i'); -define('DT_MONTHTIME1', 'n/d H:i'); -define('DT_MONTHTIME2', 'F j, H:i'); -define('DT_DATE1', 'Y-m-d'); -define('DT_DATE2', 'Ymd'); -define('DT_DATE3', 'F j, Y '); -define('DT_DATE4', 'M j'); -define('DT_TIME1', 'H:i:s'); -define('DT_TIME2', 'H:i'); + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->arrow = ' » '; +$lang->colon = '::'; +$lang->comma = ','; +$lang->dot = '.'; +$lang->at = ' at '; +$lang->downArrow = '↓'; + +$lang->ZenTaoPMS = 'ZenTaoPMS'; +$lang->welcome = "Welcome to『%s』{$lang->colon} {$lang->ZenTaoPMS}"; +$lang->myControl = "Dashboard"; +$lang->currentPos = 'Current'; +$lang->logout = 'Logout'; +$lang->login = 'Login'; +$lang->aboutZenTao = 'About'; +$lang->todayIs = '%s, '; +$lang->runInfo = "
Time: %s ms, Memory: %s KB, Queries: %s.
"; + +$lang->reset = 'Reset'; +$lang->edit = 'Edit'; +$lang->copy = 'Copy'; +$lang->delete = 'Delete'; +$lang->close = 'Close'; +$lang->link = 'Link'; +$lang->unlink = 'Unlink'; +$lang->import = 'Import'; +$lang->export = 'Export'; +$lang->setFileName = 'Filename:'; +$lang->activate = 'Activate'; +$lang->submitting = 'Saving...'; +$lang->save = 'Save'; +$lang->confirm = 'Confirm'; +$lang->preview = 'View'; +$lang->goback = 'Back'; +$lang->go = 'GO'; +$lang->more = 'More'; + +$lang->actions = 'Actions'; +$lang->comment = 'Comment'; +$lang->history = 'History'; +$lang->attatch = 'Attatch'; +$lang->reverse = '[Reverse]'; +$lang->switchDisplay= '[Toggle Show]'; +$lang->switchHelp = 'Toggle Help'; +$lang->addFiles = 'Add Files'; +$lang->files = 'Files '; +$lang->unfold = '+'; +$lang->fold = '-'; + +$lang->selectAll = 'Select All'; +$lang->notFound = 'Sorry, the object not found.'; +$lang->showAll = '++ Show All ++'; +$lang->hideClosed = '-- Hide Closed--'; + +$lang->future = 'Future'; +$lang->year = 'Year'; +$lang->workingHour = 'Hour'; + +$lang->idAB = 'ID'; +$lang->priAB = 'P'; +$lang->statusAB = 'Status'; +$lang->openedByAB = 'Open'; +$lang->assignedToAB = 'To'; +$lang->typeAB = 'Type'; + +$lang->common->common = 'Common module'; + +/* The main menu. */ +$lang->menu->my = 'Dashboard|my|index'; +$lang->menu->product = 'Product|product|index'; +$lang->menu->project = 'Project|project|index'; +$lang->menu->qa = 'Test|qa|index'; +$lang->menu->doc = 'Doc|doc|index'; +$lang->menu->company = 'Company|company|index'; +$lang->menu->admin = 'Admin|admin|index'; + +/* The objects in the search box. */ +$lang->searchObjects['bug'] = 'Bug'; +$lang->searchObjects['story'] = 'Story'; +$lang->searchObjects['task'] = 'Task'; +$lang->searchObjects['testcase'] = 'Test Case'; +$lang->searchObjects['project'] = 'Project'; +$lang->searchObjects['product'] = 'Product'; +$lang->searchObjects['user'] = 'User'; +$lang->searchObjects['build'] = 'Build'; +$lang->searchObjects['release'] = 'Release'; +$lang->searchObjects['productplan'] = 'Plan'; +$lang->searchObjects['testtask'] = 'Test Task'; +$lang->searchObjects['doc'] = 'Doc'; +$lang->searchTips = 'Id here'; + +/* File type of export. */ +$lang->exportFileTypeList['csv'] = 'csv'; +$lang->exportFileTypeList['xml'] = 'xml'; +$lang->exportFileTypeList['html'] = 'html'; + +/* Themes. */ +$lang->themes['default'] = 'Default'; +$lang->themes['green'] = 'Green'; +$lang->themes['red'] = 'Red'; +$lang->themes['classblue'] = 'Blue'; + +/* Index mododule menu. */ +$lang->index->menu->product = 'Products|product|browse'; +$lang->index->menu->project = 'Projects|project|browse'; + +/* Dashboard menu. */ +$lang->my->menu->account = '%s' . $lang->arrow; +$lang->my->menu->index = 'Index|my|index'; +$lang->my->menu->todo = array('link' => 'Todo|my|todo|', 'subModule' => 'todo'); +$lang->my->menu->task = 'Task|my|task|'; +$lang->my->menu->bug = 'Bug|my|bug|'; +$lang->my->menu->testtask = 'Test|my|testtask|'; +$lang->my->menu->story = 'Story|my|story|'; +$lang->my->menu->myProject = 'Project|my|project|'; +$lang->my->menu->dynamic = 'Dynamic|my|dynamic|'; +$lang->my->menu->profile = array('link' => 'Profile|my|profile|', 'alias' => 'editprofile'); +$lang->todo->menu = $lang->my->menu; + +/* Product menu. */ +$lang->product->menu->list = '%s'; +$lang->product->menu->story = array('link' => 'Story|product|browse|productID=%s', 'subModule' => 'story'); +$lang->product->menu->dynamic = 'Dynamic|product|dynamic|productID=%s'; +$lang->product->menu->plan = array('link' => 'Plan|productplan|browse|productID=%s', 'subModule' => 'productplan'); +$lang->product->menu->release = array('link' => 'Release|release|browse|productID=%s', 'subModule' => 'release'); +$lang->product->menu->roadmap = 'Roadmap|product|roadmap|productID=%s'; +$lang->product->menu->doc = array('link' => 'Doc|product|doc|productID=%s', 'subModule' => 'doc'); +$lang->product->menu->view = 'Info|product|view|productID=%s'; +$lang->product->menu->edit = 'Edit|product|edit|productID=%s'; +$lang->product->menu->delete = array('link' => 'Delete|product|delete|productID=%s', 'target' => 'hiddenwin'); +$lang->product->menu->module = 'Modules|tree|browse|productID=%s&view=story'; +$lang->product->menu->order = 'Order|product|order|productID=%s'; +$lang->product->menu->create = array('link' => 'New Product|product|create', 'float' => 'right'); +$lang->product->menu->project = array('link' => 'Project list|product|project|status=all&productID=%s', 'float' => 'right'); +$lang->product->menu->all = array('link' => 'All product|product|index|locate=false', 'float' => 'right'); +$lang->story->menu = $lang->product->menu; +$lang->productplan->menu = $lang->product->menu; +$lang->release->menu = $lang->product->menu; + +/* Project menu. */ +$lang->project->menu->list = '%s'; +$lang->project->menu->task = array('link' => 'Task|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); +$lang->project->menu->story = array('link' => 'Story|project|story|projectID=%s'); +$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; +$lang->project->menu->dynamic = 'Dynamic|project|dynamic|projectID=%s'; +$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); +$lang->project->menu->testtask = 'Testtask|project|testtask|projectID=%s'; +$lang->project->menu->burn = 'Burn|project|burn|projectID=%s'; +$lang->project->menu->team = array('link' => 'Team|project|team|projectID=%s', 'alias' => 'managemembers'); +$lang->project->menu->doc = array('link' => 'Doc|project|doc|porjectID=%s', 'subModule' => 'doc'); +$lang->project->menu->product = 'Link Product|project|manageproducts|projectID=%s'; +$lang->project->menu->linkstory = array('link' => 'Link Story|project|linkstory|projectID=%s'); +$lang->project->menu->view = 'Info|project|view|projectID=%s'; +$lang->project->menu->edit = 'Edit|project|edit|projectID=%s'; +$lang->project->menu->delete = array('link' => 'Delete|project|delete|projectID=%s', 'target' => 'hiddenwin'); +$lang->project->menu->order = 'Order|project|order|projectID=%s'; +$lang->project->menu->create = array('link' => 'New Project|project|create', 'float' => 'right'); +$lang->project->menu->toCopy = array('link' => 'Copy Project|project|create|projectID=©ProjectID=%s', 'float' => 'right'); +$lang->project->menu->all = array('link' => 'Project list|project|index|locate=no', 'float' => 'right'); +$lang->task->menu = $lang->project->menu; +$lang->build->menu = $lang->project->menu; + +/* QA menu. */ +$lang->bug->menu->product = '%s'; +$lang->bug->menu->bug = array('link' => 'Bug|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); +$lang->bug->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); +$lang->bug->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s'); + +$lang->testcase->menu->product = '%s'; +$lang->testcase->menu->bug = array('link' => 'Bug|bug|browse|productID=%s'); +$lang->testcase->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); +$lang->testcase->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s'); + +$lang->testtask->menu->product = '%s'; +$lang->testtask->menu->bug = array('link' => 'Bug|bug|browse|productID=%s'); +$lang->testtask->menu->testcase = array('link' => 'Test Case|testcase|browse|productID=%s'); +$lang->testtask->menu->testtask = array('link' => 'Test Task|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); + +/* Doc menu. */ +$lang->doc->menu->list = '%s'; +$lang->doc->menu->browse = array('link' => 'Doc|doc|browse|libID=%s'); +$lang->doc->menu->edit = 'Edit Library|doc|editLib|libID=%s'; +$lang->doc->menu->module = 'Modules|tree|browse|libID=%s&viewType=doc'; +$lang->doc->menu->delete = array('link' => 'Delete Library|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); +$lang->doc->menu->create = array('link' => 'New Library|doc|createLib', 'float' => 'right'); + +/* Company menu. */ +$lang->company->menu->name = '%s' . $lang->arrow; +$lang->company->menu->browseUser = array('link' => 'Users|company|browse', 'subModule' => 'user'); +$lang->company->menu->dept = array('link' => 'Department|dept|browse', 'subModule' => 'dept'); +$lang->company->menu->browseGroup = array('link' => 'Group|group|browse', 'subModule' => 'group'); +$lang->company->menu->edit = array('link' => 'Company|company|edit'); +$lang->company->menu->dynamic = 'Dynamic|company|dynamic|'; +$lang->company->menu->addGroup = array('link' => 'Add Group|group|create', 'float' => 'right'); +$lang->company->menu->addUser = array('link' => 'Add User|user|create|dept=%s&from=company', 'subModule' => 'user', 'float' => 'right'); +$lang->dept->menu = $lang->company->menu; +$lang->group->menu = $lang->company->menu; + +/* User menu. */ +$lang->user->menu->account = '%s' . $lang->arrow; +$lang->user->menu->todo = array('link' => 'Todo|user|todo|account=%s', 'subModule' => 'todo'); +$lang->user->menu->task = 'Task|user|task|account=%s'; +$lang->user->menu->bug = 'Bug|user|bug|account=%s'; +$lang->user->menu->dynamic = 'Dynamic|user|dynamic|type=today&account=%s'; +$lang->user->menu->projectList = 'Project|user|project|account=%s'; +$lang->user->menu->profile = array('link' => 'Profile|user|profile|account=%s', 'alias' => 'edit'); +$lang->user->menu->browse = array('link' => 'Manage user|company|browse|', 'float' => 'right'); + +/* Admin menu. */ +$lang->admin->menu->index = array('link' => 'Index|admin|index', 'subModule' => 'admin'); +$lang->admin->menu->extension = array('link' => 'Extension|extension|browse', 'subModule' => 'extension'); +$lang->admin->menu->editor = array('link' => 'Extension editor|editor|index', 'subModule' => 'editor'); +$lang->admin->menu->mail = array('link' => 'ConfigEmail|mail|set', 'subModule' => 'mail'); +$lang->admin->menu->convert = array('link' => 'Import|convert|index', 'subModule' => 'convert'); +$lang->admin->menu->trashes = array('link' => 'Trash|action|trash', 'subModule' => 'action'); +$lang->convert->menu = $lang->admin->menu; +$lang->upgrade->menu = $lang->admin->menu; +$lang->action->menu = $lang->admin->menu; +$lang->extension->menu = $lang->admin->menu; +$lang->editor->menu = $lang->admin->menu; +$lang->mail->menu = $lang->admin->menu; + +/* Groups. */ +$lang->menugroup->release = 'product'; +$lang->menugroup->story = 'product'; +$lang->menugroup->productplan = 'product'; +$lang->menugroup->task = 'project'; +$lang->menugroup->build = 'project'; +$lang->menugroup->convert = 'admin'; +$lang->menugroup->upgrade = 'admin'; +$lang->menugroup->user = 'company'; +$lang->menugroup->group = 'company'; +$lang->menugroup->bug = 'qa'; +$lang->menugroup->testcase = 'qa'; +$lang->menugroup->testtask = 'qa'; +$lang->menugroup->people = 'company'; +$lang->menugroup->dept = 'company'; +$lang->menugroup->todo = 'my'; +$lang->menugroup->action = 'admin'; +$lang->menugroup->extension = 'admin'; +$lang->menugroup->editor = 'admin'; +$lang->menugroup->mail = 'admin'; + +/* Error info. */ +$lang->error->companyNotFound = "The domain %s does not exist."; +$lang->error->length = array("『%s』length should be『%s』", "『%s』length should between『%s』and 『%s』."); +$lang->error->reg = "『%s』should like『%s』"; +$lang->error->unique = "『%s』has『%s』already."; +$lang->error->gt = "『%s』must great than『%s』."; +$lang->error->notempty = "『%s』can not be empty."; +$lang->error->empty = "『%s』 must be empty."; +$lang->error->equal = "『%s』must be『%s』."; +$lang->error->int = array("『%s』should be interger", "『%s』should between『%s-%s』."); +$lang->error->float = "『%s』should be a interger or float."; +$lang->error->email = "『%s』should be email."; +$lang->error->date = "『%s』should be date"; +$lang->error->account = "『%s』should be a valid account."; +$lang->error->passwordsame = "Two passwords must be the same"; +$lang->error->passwordrule = "Password should more than six letters."; +$lang->error->accessDenied = 'No purview'; + +/* Pager. */ +$lang->pager->noRecord = "No records yet."; +$lang->pager->digest = "%s records, %s per page, %s/%s "; +$lang->pager->first = "First"; +$lang->pager->pre = "Previous"; +$lang->pager->next = "Next"; +$lang->pager->last = "Last"; +$lang->pager->locate = "GO!"; + +$lang->zentaoSite = "Official Site"; +$lang->chinaScrum = "Scrum community "; +$lang->agileTraining = "Training "; +$lang->donate = "Donate "; +$lang->zentaoKeywords = "Open Source Project Management System"; +$lang->zentaoDESC = "ZenTaoPMS is an open sourced project management system."; + + + +/* Date times. */ +define('DT_DATETIME1', 'Y-m-d H:i:s'); +define('DT_DATETIME2', 'y-m-d H:i'); +define('DT_MONTHTIME1', 'n/d H:i'); +define('DT_MONTHTIME2', 'F j, H:i'); +define('DT_DATE1', 'Y-m-d'); +define('DT_DATE2', 'Ymd'); +define('DT_DATE3', 'F j, Y '); +define('DT_DATE4', 'M j'); +define('DT_TIME1', 'H:i:s'); +define('DT_TIME2', 'H:i'); diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index c2319709cb..11dd91b3b5 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -1,300 +1,300 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->arrow = ' » '; -$lang->colon = '::'; -$lang->comma = ','; -$lang->dot = '。'; -$lang->at = ' 于 '; -$lang->downArrow = '↓'; - -$lang->ZenTaoPMS = '禅道管理'; -$lang->welcome = "欢迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}"; -$lang->myControl = "我的地盘"; -$lang->currentPos = '当前位置:'; -$lang->logout = '退出'; -$lang->login = '登录'; -$lang->aboutZenTao = '关于'; -$lang->todayIs = '今天是%s,'; -$lang->runInfo = "
时间: %s 毫秒, 内存: %s KB, 查询: %s.
"; - -$lang->reset = '重填'; -$lang->edit = '编辑'; -$lang->copy = '复制'; -$lang->delete = '删除'; -$lang->close = '关闭'; -$lang->link = '关联'; -$lang->unlink = '移除'; -$lang->import = '导入'; -$lang->export = '导出'; -$lang->setFileName = '文件名:'; -$lang->activate = '激活'; -$lang->submitting = '稍候...'; -$lang->save = '保存'; -$lang->confirm = '确认'; -$lang->preview = '查看'; -$lang->goback = '返回'; -$lang->go = 'GO'; -$lang->more = '更多'; - -$lang->actions = '操作'; -$lang->comment = '备注'; -$lang->history = '历史记录'; -$lang->attatch = '附件'; -$lang->reverse = '[切换顺序]'; -$lang->switchDisplay= '[切换显示]'; -$lang->switchHelp = '切换帮助'; -$lang->addFiles = '上传了附件 '; -$lang->files = '附件 '; -$lang->unfold = '+'; -$lang->fold = '-'; - -$lang->selectAll = '全选'; -$lang->notFound = '抱歉,您访问的对象并不存在!'; -$lang->showAll = '++ 全部显示 ++'; -$lang->hideClosed = '-- 隐藏已结束 --'; - -$lang->future = '未来'; -$lang->year = '年'; -$lang->workingHour = '工时'; - -$lang->idAB = 'ID'; -$lang->priAB = 'P'; -$lang->statusAB = '状态'; -$lang->openedByAB = '创建'; -$lang->assignedToAB = '指派'; -$lang->typeAB = '类型'; - -$lang->common->common = '公有模块'; - -/* 主导航菜单。*/ -$lang->menu->my = '我的地盘|my|index'; -$lang->menu->product = '产品视图|product|index'; -$lang->menu->project = '项目视图|project|index'; -$lang->menu->qa = '测试视图|qa|index'; -$lang->menu->doc = '文档视图|doc|index'; -$lang->menu->company = '组织视图|company|index'; -$lang->menu->admin = '后台管理|admin|index'; - -/* 查询条中可以选择的对象列表。*/ -$lang->searchObjects['bug'] = 'B:Bug'; -$lang->searchObjects['story'] = 'S:需求'; -$lang->searchObjects['task'] = 'T:任务'; -$lang->searchObjects['testcase'] = 'C:用例'; -$lang->searchObjects['project'] = 'P:项目'; -$lang->searchObjects['product'] = 'P:产品'; -$lang->searchObjects['user'] = 'U:用户'; -$lang->searchObjects['build'] = 'B:Build'; -$lang->searchObjects['release'] = 'R:发布'; -$lang->searchObjects['productplan'] = 'P:产品计划'; -$lang->searchObjects['testtask'] = 'T:测试任务'; -$lang->searchObjects['doc'] = 'D:文档'; -$lang->searchTips = '输入编号'; - -/* 导出文件的类型列表。*/ -$lang->exportFileTypeList['csv'] = 'csv'; -$lang->exportFileTypeList['xml'] = 'xml'; -$lang->exportFileTypeList['html'] = 'html'; - -/* 风格列表。*/ -$lang->themes['default'] = '默认'; -$lang->themes['green'] = '绿色'; -$lang->themes['red'] = '红色'; -$lang->themes['classblue'] = '经典蓝'; - -/* 首页菜单设置。*/ -$lang->index->menu->product = '浏览产品|product|browse'; -$lang->index->menu->project = '浏览项目|project|browse'; - -/* 我的地盘菜单设置。*/ -$lang->my->menu->account = '%s' . $lang->arrow; -$lang->my->menu->index = '首页|my|index'; -$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo'); -$lang->my->menu->task = '我的任务|my|task|'; -$lang->my->menu->bug = '我的Bug|my|bug|'; -$lang->my->menu->testtask = '我的测试|my|testtask|'; -$lang->my->menu->story = '我的需求|my|story|'; -$lang->my->menu->myProject = '我的项目|my|project|'; -$lang->my->menu->dynamic = '我的动态|my|dynamic|'; -$lang->my->menu->profile = array('link' => '我的档案|my|profile|', 'alias' => 'editprofile'); -$lang->todo->menu = $lang->my->menu; - -/* 产品视图设置。*/ -$lang->product->menu->list = '%s'; -$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story'); -$lang->product->menu->dynamic = '动态|product|dynamic|productID=%s'; -$lang->product->menu->plan = array('link' => '计划|productplan|browse|productID=%s', 'subModule' => 'productplan'); -$lang->product->menu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release'); -$lang->product->menu->roadmap = '路线图|product|roadmap|productID=%s'; -$lang->product->menu->doc = array('link' => '文档|product|doc|productID=%s', 'subModule' => 'doc'); -$lang->product->menu->view = '概况|product|view|productID=%s'; -$lang->product->menu->edit = '编辑|product|edit|productID=%s'; -$lang->product->menu->delete = array('link' => '删除|product|delete|productID=%s', 'target' => 'hiddenwin'); -$lang->product->menu->module = '模块|tree|browse|productID=%s&view=story'; -$lang->product->menu->order = '排序|product|order|productID=%s'; -$lang->product->menu->create = array('link' => '新增产品|product|create', 'float' => 'right'); -$lang->product->menu->project = array('link' => '项目列表|product|project|status=all&productID=%s', 'float' => 'right'); -$lang->product->menu->all = array('link' => '所有产品|product|index|locate=false', 'float' => 'right'); -$lang->story->menu = $lang->product->menu; -$lang->productplan->menu = $lang->product->menu; -$lang->release->menu = $lang->product->menu; - -/* 项目视图菜单设置。*/ -$lang->project->menu->list = '%s'; -$lang->project->menu->task = array('link' => '任务|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); -$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s'); -$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; -$lang->project->menu->dynamic = '动态|project|dynamic|projectID=%s'; -$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); -$lang->project->menu->testtask = '测试申请|project|testtask|projectID=%s'; -$lang->project->menu->burn = '燃尽图|project|burn|projectID=%s'; -$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers'); -$lang->project->menu->doc = array('link' => '文档|project|doc|porjectID=%s', 'subModule' => 'doc'); -$lang->project->menu->product = '产品|project|manageproducts|projectID=%s'; -$lang->project->menu->linkstory = array('link' => '关联需求|project|linkstory|projectID=%s'); -$lang->project->menu->view = '概况|project|view|projectID=%s'; -$lang->project->menu->edit = '编辑|project|edit|projectID=%s'; -$lang->project->menu->delete = array('link' => '删除|project|delete|projectID=%s', 'target' => 'hiddenwin'); -$lang->project->menu->order = '排序|project|order|projectID=%s'; -$lang->project->menu->create = array('link' => '新增项目|project|create', 'float' => 'right'); -$lang->project->menu->toCopy = array('link' => '复制项目|project|create|projectID=©ProjectID=%s', 'float' => 'right'); -$lang->project->menu->all = array('link' => '所有项目|project|index|locate=false', 'float' => 'right'); -$lang->task->menu = $lang->project->menu; -$lang->build->menu = $lang->project->menu; - -/* QA视图菜单设置。*/ -$lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); -$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); -$lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); - -$lang->testcase->menu->product = '%s'; -$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); -$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); -$lang->testcase->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); - -$lang->testtask->menu->product = '%s'; -$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); -$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s'); -$lang->testtask->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); - -/* 文档视图菜单设置。*/ -$lang->doc->menu->list = '%s'; -$lang->doc->menu->browse = array('link' => '文档列表|doc|browse|libID=%s'); -$lang->doc->menu->edit = '编辑文档库|doc|editLib|libID=%s'; -$lang->doc->menu->module = '维护模块|tree|browse|libID=%s&viewType=doc'; -$lang->doc->menu->delete = array('link' => '删除文档库|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); -$lang->doc->menu->create = array('link' => '新增文档库|doc|createLib', 'float' => 'right'); - -/* 组织结构视图菜单设置。*/ -$lang->company->menu->name = '%s' . $lang->arrow; -$lang->company->menu->browseUser = array('link' => '用户列表|company|browse', 'subModule' => 'user'); -$lang->company->menu->dept = array('link' => '部门维护|dept|browse', 'subModule' => 'dept'); -$lang->company->menu->browseGroup = array('link' => '权限分组|group|browse', 'subModule' => 'group'); -$lang->company->menu->edit = array('link' => '公司管理|company|edit'); -$lang->company->menu->dynamic = '组织动态|company|dynamic|'; -$lang->company->menu->addGroup = array('link' => '添加分组|group|create', 'float' => 'right'); -$lang->company->menu->addUser = array('link' => '添加用户|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right'); -$lang->dept->menu = $lang->company->menu; -$lang->group->menu = $lang->company->menu; - -/* 用户信息菜单设置。*/ -$lang->user->menu->account = '%s' . $lang->arrow; -$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo'); -$lang->user->menu->task = '任务列表|user|task|account=%s'; -$lang->user->menu->bug = 'Bug列表|user|bug|account=%s'; -$lang->user->menu->dynamic = '用户动态|user|dynamic|type=today&account=%s'; -$lang->user->menu->projectList = '项目列表|user|project|account=%s'; -$lang->user->menu->profile = array('link' => '用户信息|user|profile|account=%s', 'alias' => 'edit'); -$lang->user->menu->browse = array('link' => '用户管理|company|browse|', 'float' => 'right'); - -/* 后台管理菜单设置。*/ -$lang->admin->menu->index = array('link' => '首页|admin|index', 'subModule' => 'admin'); -$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension'); -$lang->admin->menu->editor = array('link' => '扩展编辑器|editor|index', 'subModule' => 'editor'); -$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail'); -$lang->admin->menu->convert = array('link' => '从其他系统导入|convert|index', 'subModule' => 'convert'); -$lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action'); -$lang->convert->menu = $lang->admin->menu; -$lang->upgrade->menu = $lang->admin->menu; -$lang->action->menu = $lang->admin->menu; -$lang->extension->menu = $lang->admin->menu; -$lang->editor->menu = $lang->admin->menu; -$lang->mail->menu = $lang->admin->menu; - -/*菜单设置:分组设置。*/ -$lang->menugroup->release = 'product'; -$lang->menugroup->story = 'product'; -$lang->menugroup->productplan = 'product'; -$lang->menugroup->task = 'project'; -$lang->menugroup->build = 'project'; -$lang->menugroup->convert = 'admin'; -$lang->menugroup->upgrade = 'admin'; -$lang->menugroup->user = 'company'; -$lang->menugroup->group = 'company'; -$lang->menugroup->bug = 'qa'; -$lang->menugroup->testcase = 'qa'; -$lang->menugroup->testtask = 'qa'; -$lang->menugroup->people = 'company'; -$lang->menugroup->dept = 'company'; -$lang->menugroup->todo = 'my'; -$lang->menugroup->action = 'admin'; -$lang->menugroup->extension = 'admin'; -$lang->menugroup->editor = 'admin'; -$lang->menugroup->mail = 'admin'; - -/* 错误提示信息。*/ -$lang->error->companyNotFound = "您访问的域名 %s 没有对应的公司。"; -$lang->error->length = array("『%s』长度错误,应当为『%s』", "『%s』长度应当不超过『%s』,且不小于『%s』。"); -$lang->error->reg = "『%s』不符合格式,应当为:『%s』。"; -$lang->error->unique = "『%s』已经有『%s』这条记录了。"; -$lang->error->gt = "『%s』应当大于『%s』。"; -$lang->error->notempty = "『%s』不能为空。"; -$lang->error->empty = "『%s』必须为空。"; -$lang->error->equal = "『%s』必须为『%s』。"; -$lang->error->int = array("『%s』应当是数字。", "『%s』应当介于『%s-%s』之间。"); -$lang->error->float = "『%s』应当是数字,可以是小数。"; -$lang->error->email = "『%s』应当为合法的EMAIL。"; -$lang->error->date = "『%s』应当为合法的日期。"; -$lang->error->account = "『%s』应当为合法的用户名。"; -$lang->error->passwordsame = "两次密码应当相等。"; -$lang->error->passwordrule = "密码应该符合规则,长度至少为六位。"; -$lang->error->accessDenied = '您没有访问权限'; - -/* 分页信息。*/ -$lang->pager->noRecord = "暂时没有记录"; -$lang->pager->digest = "共%s条记录,每页 %s条,页面:%s/%s "; -$lang->pager->first = "首页"; -$lang->pager->pre = "上页"; -$lang->pager->next = "下页"; -$lang->pager->last = "末页"; -$lang->pager->locate = "GO!"; - -$lang->zentaoSite = "官方网站"; -$lang->chinaScrum = "Scrum社区 "; -$lang->agileTraining = "培训 "; -$lang->donate = "捐助禅道 "; -$lang->zentaoKeywords = "开源项目管理软件,项目管理,项目管理软件,pmp,pms,php框架,国产php框架,scrum工具,scrum管理工具,scrum管理软件,敏捷项目管理,禅道"; -$lang->zentaoDESC = "禅道项目管理软件(ZenTaoPMS)是一款国产的,基于LGPL协议,开源免费的项目管理软件(工具、系统),同时也是一款scrum管理工具。 - 它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选。禅道项目管理软件使用PHP + MySQL开发, -基于自主的PHP开发框架──ZenTaoPHP而成。第三方开发者或者企业可以非常方便的开发插件或者进行定制。禅道在手,项目无忧!"; - -/* 时间格式设置。*/ -define('DT_DATETIME1', 'Y-m-d H:i:s'); -define('DT_DATETIME2', 'y-m-d H:i'); -define('DT_MONTHTIME1', 'n/d H:i'); -define('DT_MONTHTIME2', 'n月d日 H:i'); -define('DT_DATE1', 'Y-m-d'); -define('DT_DATE2', 'Ymd'); -define('DT_DATE3', 'Y年m月d日'); -define('DT_DATE4', 'n月j日'); -define('DT_TIME1', 'H:i:s'); -define('DT_TIME2', 'H:i'); + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->arrow = ' » '; +$lang->colon = '::'; +$lang->comma = ','; +$lang->dot = '。'; +$lang->at = ' 于 '; +$lang->downArrow = '↓'; + +$lang->ZenTaoPMS = '禅道管理'; +$lang->welcome = "欢迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}"; +$lang->myControl = "我的地盘"; +$lang->currentPos = '当前位置:'; +$lang->logout = '退出'; +$lang->login = '登录'; +$lang->aboutZenTao = '关于'; +$lang->todayIs = '今天是%s,'; +$lang->runInfo = "
时间: %s 毫秒, 内存: %s KB, 查询: %s.
"; + +$lang->reset = '重填'; +$lang->edit = '编辑'; +$lang->copy = '复制'; +$lang->delete = '删除'; +$lang->close = '关闭'; +$lang->link = '关联'; +$lang->unlink = '移除'; +$lang->import = '导入'; +$lang->export = '导出'; +$lang->setFileName = '文件名:'; +$lang->activate = '激活'; +$lang->submitting = '稍候...'; +$lang->save = '保存'; +$lang->confirm = '确认'; +$lang->preview = '查看'; +$lang->goback = '返回'; +$lang->go = 'GO'; +$lang->more = '更多'; + +$lang->actions = '操作'; +$lang->comment = '备注'; +$lang->history = '历史记录'; +$lang->attatch = '附件'; +$lang->reverse = '[切换顺序]'; +$lang->switchDisplay= '[切换显示]'; +$lang->switchHelp = '切换帮助'; +$lang->addFiles = '上传了附件 '; +$lang->files = '附件 '; +$lang->unfold = '+'; +$lang->fold = '-'; + +$lang->selectAll = '全选'; +$lang->notFound = '抱歉,您访问的对象并不存在!'; +$lang->showAll = '++ 全部显示 ++'; +$lang->hideClosed = '-- 隐藏已结束 --'; + +$lang->future = '未来'; +$lang->year = '年'; +$lang->workingHour = '工时'; + +$lang->idAB = 'ID'; +$lang->priAB = 'P'; +$lang->statusAB = '状态'; +$lang->openedByAB = '创建'; +$lang->assignedToAB = '指派'; +$lang->typeAB = '类型'; + +$lang->common->common = '公有模块'; + +/* 主导航菜单。*/ +$lang->menu->my = '我的地盘|my|index'; +$lang->menu->product = '产品视图|product|index'; +$lang->menu->project = '项目视图|project|index'; +$lang->menu->qa = '测试视图|qa|index'; +$lang->menu->doc = '文档视图|doc|index'; +$lang->menu->company = '组织视图|company|index'; +$lang->menu->admin = '后台管理|admin|index'; + +/* 查询条中可以选择的对象列表。*/ +$lang->searchObjects['bug'] = 'B:Bug'; +$lang->searchObjects['story'] = 'S:需求'; +$lang->searchObjects['task'] = 'T:任务'; +$lang->searchObjects['testcase'] = 'C:用例'; +$lang->searchObjects['project'] = 'P:项目'; +$lang->searchObjects['product'] = 'P:产品'; +$lang->searchObjects['user'] = 'U:用户'; +$lang->searchObjects['build'] = 'B:Build'; +$lang->searchObjects['release'] = 'R:发布'; +$lang->searchObjects['productplan'] = 'P:产品计划'; +$lang->searchObjects['testtask'] = 'T:测试任务'; +$lang->searchObjects['doc'] = 'D:文档'; +$lang->searchTips = '输入编号'; + +/* 导出文件的类型列表。*/ +$lang->exportFileTypeList['csv'] = 'csv'; +$lang->exportFileTypeList['xml'] = 'xml'; +$lang->exportFileTypeList['html'] = 'html'; + +/* 风格列表。*/ +$lang->themes['default'] = '默认'; +$lang->themes['green'] = '绿色'; +$lang->themes['red'] = '红色'; +$lang->themes['classblue'] = '经典蓝'; + +/* 首页菜单设置。*/ +$lang->index->menu->product = '浏览产品|product|browse'; +$lang->index->menu->project = '浏览项目|project|browse'; + +/* 我的地盘菜单设置。*/ +$lang->my->menu->account = '%s' . $lang->arrow; +$lang->my->menu->index = '首页|my|index'; +$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo'); +$lang->my->menu->task = '我的任务|my|task|'; +$lang->my->menu->bug = '我的Bug|my|bug|'; +$lang->my->menu->testtask = '我的测试|my|testtask|'; +$lang->my->menu->story = '我的需求|my|story|'; +$lang->my->menu->myProject = '我的项目|my|project|'; +$lang->my->menu->dynamic = '我的动态|my|dynamic|'; +$lang->my->menu->profile = array('link' => '我的档案|my|profile|', 'alias' => 'editprofile'); +$lang->todo->menu = $lang->my->menu; + +/* 产品视图设置。*/ +$lang->product->menu->list = '%s'; +$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story'); +$lang->product->menu->dynamic = '动态|product|dynamic|productID=%s'; +$lang->product->menu->plan = array('link' => '计划|productplan|browse|productID=%s', 'subModule' => 'productplan'); +$lang->product->menu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release'); +$lang->product->menu->roadmap = '路线图|product|roadmap|productID=%s'; +$lang->product->menu->doc = array('link' => '文档|product|doc|productID=%s', 'subModule' => 'doc'); +$lang->product->menu->view = '概况|product|view|productID=%s'; +$lang->product->menu->edit = '编辑|product|edit|productID=%s'; +$lang->product->menu->delete = array('link' => '删除|product|delete|productID=%s', 'target' => 'hiddenwin'); +$lang->product->menu->module = '模块|tree|browse|productID=%s&view=story'; +$lang->product->menu->order = '排序|product|order|productID=%s'; +$lang->product->menu->create = array('link' => '新增产品|product|create', 'float' => 'right'); +$lang->product->menu->project = array('link' => '项目列表|product|project|status=all&productID=%s', 'float' => 'right'); +$lang->product->menu->all = array('link' => '所有产品|product|index|locate=false', 'float' => 'right'); +$lang->story->menu = $lang->product->menu; +$lang->productplan->menu = $lang->product->menu; +$lang->release->menu = $lang->product->menu; + +/* 项目视图菜单设置。*/ +$lang->project->menu->list = '%s'; +$lang->project->menu->task = array('link' => '任务|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); +$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s'); +$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; +$lang->project->menu->dynamic = '动态|project|dynamic|projectID=%s'; +$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); +$lang->project->menu->testtask = '测试申请|project|testtask|projectID=%s'; +$lang->project->menu->burn = '燃尽图|project|burn|projectID=%s'; +$lang->project->menu->team = array('link' => '团队|project|team|projectID=%s', 'alias' => 'managemembers'); +$lang->project->menu->doc = array('link' => '文档|project|doc|porjectID=%s', 'subModule' => 'doc'); +$lang->project->menu->product = '产品|project|manageproducts|projectID=%s'; +$lang->project->menu->linkstory = array('link' => '关联需求|project|linkstory|projectID=%s'); +$lang->project->menu->view = '概况|project|view|projectID=%s'; +$lang->project->menu->edit = '编辑|project|edit|projectID=%s'; +$lang->project->menu->delete = array('link' => '删除|project|delete|projectID=%s', 'target' => 'hiddenwin'); +$lang->project->menu->order = '排序|project|order|projectID=%s'; +$lang->project->menu->create = array('link' => '新增项目|project|create', 'float' => 'right'); +$lang->project->menu->toCopy = array('link' => '复制项目|project|create|projectID=©ProjectID=%s', 'float' => 'right'); +$lang->project->menu->all = array('link' => '所有项目|project|index|locate=false', 'float' => 'right'); +$lang->task->menu = $lang->project->menu; +$lang->build->menu = $lang->project->menu; + +/* QA视图菜单设置。*/ +$lang->bug->menu->product = '%s'; +$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); +$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); +$lang->bug->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); + +$lang->testcase->menu->product = '%s'; +$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); +$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); +$lang->testcase->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s'); + +$lang->testtask->menu->product = '%s'; +$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); +$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s'); +$lang->testtask->menu->testtask = array('link' => '测试任务|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); + +/* 文档视图菜单设置。*/ +$lang->doc->menu->list = '%s'; +$lang->doc->menu->browse = array('link' => '文档列表|doc|browse|libID=%s'); +$lang->doc->menu->edit = '编辑文档库|doc|editLib|libID=%s'; +$lang->doc->menu->module = '维护模块|tree|browse|libID=%s&viewType=doc'; +$lang->doc->menu->delete = array('link' => '删除文档库|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); +$lang->doc->menu->create = array('link' => '新增文档库|doc|createLib', 'float' => 'right'); + +/* 组织结构视图菜单设置。*/ +$lang->company->menu->name = '%s' . $lang->arrow; +$lang->company->menu->browseUser = array('link' => '用户列表|company|browse', 'subModule' => 'user'); +$lang->company->menu->dept = array('link' => '部门维护|dept|browse', 'subModule' => 'dept'); +$lang->company->menu->browseGroup = array('link' => '权限分组|group|browse', 'subModule' => 'group'); +$lang->company->menu->edit = array('link' => '公司管理|company|edit'); +$lang->company->menu->dynamic = '组织动态|company|dynamic|'; +$lang->company->menu->addGroup = array('link' => '添加分组|group|create', 'float' => 'right'); +$lang->company->menu->addUser = array('link' => '添加用户|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right'); +$lang->dept->menu = $lang->company->menu; +$lang->group->menu = $lang->company->menu; + +/* 用户信息菜单设置。*/ +$lang->user->menu->account = '%s' . $lang->arrow; +$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo'); +$lang->user->menu->task = '任务列表|user|task|account=%s'; +$lang->user->menu->bug = 'Bug列表|user|bug|account=%s'; +$lang->user->menu->dynamic = '用户动态|user|dynamic|type=today&account=%s'; +$lang->user->menu->projectList = '项目列表|user|project|account=%s'; +$lang->user->menu->profile = array('link' => '用户信息|user|profile|account=%s', 'alias' => 'edit'); +$lang->user->menu->browse = array('link' => '用户管理|company|browse|', 'float' => 'right'); + +/* 后台管理菜单设置。*/ +$lang->admin->menu->index = array('link' => '首页|admin|index', 'subModule' => 'admin'); +$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension'); +$lang->admin->menu->editor = array('link' => '扩展编辑器|editor|index', 'subModule' => 'editor'); +$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail'); +$lang->admin->menu->convert = array('link' => '从其他系统导入|convert|index', 'subModule' => 'convert'); +$lang->admin->menu->trashes = array('link' => '回收站|action|trash', 'subModule' => 'action'); +$lang->convert->menu = $lang->admin->menu; +$lang->upgrade->menu = $lang->admin->menu; +$lang->action->menu = $lang->admin->menu; +$lang->extension->menu = $lang->admin->menu; +$lang->editor->menu = $lang->admin->menu; +$lang->mail->menu = $lang->admin->menu; + +/*菜单设置:分组设置。*/ +$lang->menugroup->release = 'product'; +$lang->menugroup->story = 'product'; +$lang->menugroup->productplan = 'product'; +$lang->menugroup->task = 'project'; +$lang->menugroup->build = 'project'; +$lang->menugroup->convert = 'admin'; +$lang->menugroup->upgrade = 'admin'; +$lang->menugroup->user = 'company'; +$lang->menugroup->group = 'company'; +$lang->menugroup->bug = 'qa'; +$lang->menugroup->testcase = 'qa'; +$lang->menugroup->testtask = 'qa'; +$lang->menugroup->people = 'company'; +$lang->menugroup->dept = 'company'; +$lang->menugroup->todo = 'my'; +$lang->menugroup->action = 'admin'; +$lang->menugroup->extension = 'admin'; +$lang->menugroup->editor = 'admin'; +$lang->menugroup->mail = 'admin'; + +/* 错误提示信息。*/ +$lang->error->companyNotFound = "您访问的域名 %s 没有对应的公司。"; +$lang->error->length = array("『%s』长度错误,应当为『%s』", "『%s』长度应当不超过『%s』,且不小于『%s』。"); +$lang->error->reg = "『%s』不符合格式,应当为:『%s』。"; +$lang->error->unique = "『%s』已经有『%s』这条记录了。"; +$lang->error->gt = "『%s』应当大于『%s』。"; +$lang->error->notempty = "『%s』不能为空。"; +$lang->error->empty = "『%s』必须为空。"; +$lang->error->equal = "『%s』必须为『%s』。"; +$lang->error->int = array("『%s』应当是数字。", "『%s』应当介于『%s-%s』之间。"); +$lang->error->float = "『%s』应当是数字,可以是小数。"; +$lang->error->email = "『%s』应当为合法的EMAIL。"; +$lang->error->date = "『%s』应当为合法的日期。"; +$lang->error->account = "『%s』应当为合法的用户名。"; +$lang->error->passwordsame = "两次密码应当相等。"; +$lang->error->passwordrule = "密码应该符合规则,长度至少为六位。"; +$lang->error->accessDenied = '您没有访问权限'; + +/* 分页信息。*/ +$lang->pager->noRecord = "暂时没有记录"; +$lang->pager->digest = "共%s条记录,每页 %s条,页面:%s/%s "; +$lang->pager->first = "首页"; +$lang->pager->pre = "上页"; +$lang->pager->next = "下页"; +$lang->pager->last = "末页"; +$lang->pager->locate = "GO!"; + +$lang->zentaoSite = "官方网站"; +$lang->chinaScrum = "Scrum社区 "; +$lang->agileTraining = "培训 "; +$lang->donate = "捐助禅道 "; +$lang->zentaoKeywords = "开源项目管理软件,项目管理,项目管理软件,pmp,pms,php框架,国产php框架,scrum工具,scrum管理工具,scrum管理软件,敏捷项目管理,禅道"; +$lang->zentaoDESC = "禅道项目管理软件(ZenTaoPMS)是一款国产的,基于LGPL协议,开源免费的项目管理软件(工具、系统),同时也是一款scrum管理工具。 + 它集产品管理、项目管理、测试管理于一体,同时还包含了事务管理、组织管理等诸多功能,是中小型企业项目管理的首选。禅道项目管理软件使用PHP + MySQL开发, +基于自主的PHP开发框架──ZenTaoPHP而成。第三方开发者或者企业可以非常方便的开发插件或者进行定制。禅道在手,项目无忧!"; + +/* 时间格式设置。*/ +define('DT_DATETIME1', 'Y-m-d H:i:s'); +define('DT_DATETIME2', 'y-m-d H:i'); +define('DT_MONTHTIME1', 'n/d H:i'); +define('DT_MONTHTIME2', 'n月d日 H:i'); +define('DT_DATE1', 'Y-m-d'); +define('DT_DATE2', 'Ymd'); +define('DT_DATE3', 'Y年m月d日'); +define('DT_DATE4', 'n月j日'); +define('DT_TIME1', 'H:i:s'); +define('DT_TIME2', 'H:i'); diff --git a/module/common/lang/zh-tw.php b/module/common/lang/zh-tw.php index 3ebf0ad345..6cbfe12d98 100644 --- a/module/common/lang/zh-tw.php +++ b/module/common/lang/zh-tw.php @@ -1,300 +1,300 @@ - - * @package ZenTaoPMS - * @version $Id: zh-tw.php 2600 2012-02-21 04:35:05Z wyd621@gmail.com $ - * @link http://www.zentao.net - */ -$lang->arrow = ' » '; -$lang->colon = '::'; -$lang->comma = ','; -$lang->dot = '。'; -$lang->at = ' 于 '; -$lang->downArrow = '↓'; - -$lang->ZenTaoPMS = '禪道管理'; -$lang->welcome = "歡迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}"; -$lang->myControl = "我的地盤"; -$lang->currentPos = '當前位置:'; -$lang->logout = '退出'; -$lang->login = '登錄'; -$lang->aboutZenTao = '關於'; -$lang->todayIs = '今天是%s,'; -$lang->runInfo = "
時間: %s 毫秒, 內存: %s KB, 查詢: %s.
"; - -$lang->reset = '重填'; -$lang->edit = '編輯'; -$lang->copy = '複製'; -$lang->delete = '刪除'; -$lang->close = '關閉'; -$lang->link = '關聯'; -$lang->unlink = '移除'; -$lang->import = '導入'; -$lang->export = '導出'; -$lang->setFileName = '檔案名:'; -$lang->activate = '激活'; -$lang->submitting = '稍候...'; -$lang->save = '保存'; -$lang->confirm = '確認'; -$lang->preview = '查看'; -$lang->goback = '返回'; -$lang->go = 'GO'; -$lang->more = '更多'; - -$lang->actions = '操作'; -$lang->comment = '備註'; -$lang->history = '歷史記錄'; -$lang->attatch = '附件'; -$lang->reverse = '[切換順序]'; -$lang->switchDisplay= '[切換顯示]'; -$lang->switchHelp = '切換幫助'; -$lang->addFiles = '上傳了附件 '; -$lang->files = '附件 '; -$lang->unfold = '+'; -$lang->fold = '-'; - -$lang->selectAll = '全選'; -$lang->notFound = '抱歉,您訪問的對象並不存在!'; -$lang->showAll = '++ 全部顯示 ++'; -$lang->hideClosed = '-- 隱藏已結束 --'; - -$lang->future = '未來'; -$lang->year = '年'; -$lang->workingHour = '工時'; - -$lang->idAB = 'ID'; -$lang->priAB = 'P'; -$lang->statusAB = '狀態'; -$lang->openedByAB = '創建'; -$lang->assignedToAB = '指派'; -$lang->typeAB = '類型'; - -$lang->common->common = '公有模組'; - -/* 主導航菜單。*/ -$lang->menu->my = '我的地盤|my|index'; -$lang->menu->product = '產品視圖|product|index'; -$lang->menu->project = '項目視圖|project|index'; -$lang->menu->qa = '測試視圖|qa|index'; -$lang->menu->doc = '文檔視圖|doc|index'; -$lang->menu->company = '組織視圖|company|index'; -$lang->menu->admin = '後台管理|admin|index'; - -/* 查詢條中可以選擇的對象列表。*/ -$lang->searchObjects['bug'] = 'B:Bug'; -$lang->searchObjects['story'] = 'S:需求'; -$lang->searchObjects['task'] = 'T:任務'; -$lang->searchObjects['testcase'] = 'C:用例'; -$lang->searchObjects['project'] = 'P:項目'; -$lang->searchObjects['product'] = 'P:產品'; -$lang->searchObjects['user'] = 'U:用戶'; -$lang->searchObjects['build'] = 'B:Build'; -$lang->searchObjects['release'] = 'R:發佈'; -$lang->searchObjects['productplan'] = 'P:產品計劃'; -$lang->searchObjects['testtask'] = 'T:測試任務'; -$lang->searchObjects['doc'] = 'D:文檔'; -$lang->searchTips = '輸入編號'; - -/* 導出檔案的類型列表。*/ -$lang->exportFileTypeList['csv'] = 'csv'; -$lang->exportFileTypeList['xml'] = 'xml'; -$lang->exportFileTypeList['html'] = 'html'; - -/* 風格列表。*/ -$lang->themes['default'] = '預設'; -$lang->themes['green'] = '綠色'; -$lang->themes['red'] = '紅色'; -$lang->themes['classblue'] = '經典藍'; - -/* 首頁菜單設置。*/ -$lang->index->menu->product = '瀏覽產品|product|browse'; -$lang->index->menu->project = '瀏覽項目|project|browse'; - -/* 我的地盤菜單設置。*/ -$lang->my->menu->account = '%s' . $lang->arrow; -$lang->my->menu->index = '首頁|my|index'; -$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo'); -$lang->my->menu->task = '我的任務|my|task|'; -$lang->my->menu->bug = '我的Bug|my|bug|'; -$lang->my->menu->testtask = '我的測試|my|testtask|'; -$lang->my->menu->story = '我的需求|my|story|'; -$lang->my->menu->myProject = '我的項目|my|project|'; -$lang->my->menu->dynamic = '我的動態|my|dynamic|'; -$lang->my->menu->profile = array('link' => '我的檔案|my|profile|', 'alias' => 'editprofile'); -$lang->todo->menu = $lang->my->menu; - -/* 產品視圖設置。*/ -$lang->product->menu->list = '%s'; -$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story'); -$lang->product->menu->dynamic = '動態|product|dynamic|productID=%s'; -$lang->product->menu->plan = array('link' => '計劃|productplan|browse|productID=%s', 'subModule' => 'productplan'); -$lang->product->menu->release = array('link' => '發佈|release|browse|productID=%s', 'subModule' => 'release'); -$lang->product->menu->roadmap = '路線圖|product|roadmap|productID=%s'; -$lang->product->menu->doc = array('link' => '文檔|product|doc|productID=%s', 'subModule' => 'doc'); -$lang->product->menu->view = '概況|product|view|productID=%s'; -$lang->product->menu->edit = '編輯|product|edit|productID=%s'; -$lang->product->menu->delete = array('link' => '刪除|product|delete|productID=%s', 'target' => 'hiddenwin'); -$lang->product->menu->module = '模組|tree|browse|productID=%s&view=story'; -$lang->product->menu->order = '排序|product|order|productID=%s'; -$lang->product->menu->create = array('link' => '新增產品|product|create', 'float' => 'right'); -$lang->product->menu->project = array('link' => '項目列表|product|project|status=all&productID=%s', 'float' => 'right'); -$lang->product->menu->all = array('link' => '所有產品|product|index|locate=false', 'float' => 'right'); -$lang->story->menu = $lang->product->menu; -$lang->productplan->menu = $lang->product->menu; -$lang->release->menu = $lang->product->menu; - -/* 項目視圖菜單設置。*/ -$lang->project->menu->list = '%s'; -$lang->project->menu->task = array('link' => '任務|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); -$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s'); -$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; -$lang->project->menu->dynamic = '動態|project|dynamic|projectID=%s'; -$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); -$lang->project->menu->testtask = '測試申請|project|testtask|projectID=%s'; -$lang->project->menu->burn = '燃盡圖|project|burn|projectID=%s'; -$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers'); -$lang->project->menu->doc = array('link' => '文檔|project|doc|porjectID=%s', 'subModule' => 'doc'); -$lang->project->menu->product = '產品|project|manageproducts|projectID=%s'; -$lang->project->menu->linkstory = array('link' => '關聯需求|project|linkstory|projectID=%s'); -$lang->project->menu->view = '概況|project|view|projectID=%s'; -$lang->project->menu->edit = '編輯|project|edit|projectID=%s'; -$lang->project->menu->delete = array('link' => '刪除|project|delete|projectID=%s', 'target' => 'hiddenwin'); -$lang->project->menu->order = '排序|project|order|projectID=%s'; -$lang->project->menu->create = array('link' => '新增項目|project|create', 'float' => 'right'); -$lang->project->menu->toCopy = array('link' => '複製項目|project|create|projectID=©ProjectID=%s', 'float' => 'right'); -$lang->project->menu->all = array('link' => '所有項目|project|index|locate=false', 'float' => 'right'); -$lang->task->menu = $lang->project->menu; -$lang->build->menu = $lang->project->menu; - -/* QA視圖菜單設置。*/ -$lang->bug->menu->product = '%s'; -$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); -$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); -$lang->bug->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s'); - -$lang->testcase->menu->product = '%s'; -$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); -$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); -$lang->testcase->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s'); - -$lang->testtask->menu->product = '%s'; -$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); -$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s'); -$lang->testtask->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); - -/* 文檔視圖菜單設置。*/ -$lang->doc->menu->list = '%s'; -$lang->doc->menu->browse = array('link' => '文檔列表|doc|browse|libID=%s'); -$lang->doc->menu->edit = '編輯文檔庫|doc|editLib|libID=%s'; -$lang->doc->menu->module = '維護模組|tree|browse|libID=%s&viewType=doc'; -$lang->doc->menu->delete = array('link' => '刪除文檔庫|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); -$lang->doc->menu->create = array('link' => '新增文檔庫|doc|createLib', 'float' => 'right'); - -/* 組織結構視圖菜單設置。*/ -$lang->company->menu->name = '%s' . $lang->arrow; -$lang->company->menu->browseUser = array('link' => '用戶列表|company|browse', 'subModule' => 'user'); -$lang->company->menu->dept = array('link' => '部門維護|dept|browse', 'subModule' => 'dept'); -$lang->company->menu->browseGroup = array('link' => '權限分組|group|browse', 'subModule' => 'group'); -$lang->company->menu->edit = array('link' => '公司管理|company|edit'); -$lang->company->menu->dynamic = '組織動態|company|dynamic|'; -$lang->company->menu->addGroup = array('link' => '添加分組|group|create', 'float' => 'right'); -$lang->company->menu->addUser = array('link' => '添加用戶|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right'); -$lang->dept->menu = $lang->company->menu; -$lang->group->menu = $lang->company->menu; - -/* 用戶信息菜單設置。*/ -$lang->user->menu->account = '%s' . $lang->arrow; -$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo'); -$lang->user->menu->task = '任務列表|user|task|account=%s'; -$lang->user->menu->bug = 'Bug列表|user|bug|account=%s'; -$lang->user->menu->dynamic = '用戶動態|user|dynamic|type=today&account=%s'; -$lang->user->menu->projectList = '項目列表|user|project|account=%s'; -$lang->user->menu->profile = array('link' => '用戶信息|user|profile|account=%s', 'alias' => 'edit'); -$lang->user->menu->browse = array('link' => '用戶管理|company|browse|', 'float' => 'right'); - -/* 後台管理菜單設置。*/ -$lang->admin->menu->index = array('link' => '首頁|admin|index', 'subModule' => 'admin'); -$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension'); -$lang->admin->menu->editor = array('link' => '擴展編輯器|editor|index', 'subModule' => 'editor'); -$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail'); -$lang->admin->menu->convert = array('link' => '從其他系統導入|convert|index', 'subModule' => 'convert'); -$lang->admin->menu->trashes = array('link' => '資源回收筒|action|trash', 'subModule' => 'action'); -$lang->convert->menu = $lang->admin->menu; -$lang->upgrade->menu = $lang->admin->menu; -$lang->action->menu = $lang->admin->menu; -$lang->extension->menu = $lang->admin->menu; -$lang->editor->menu = $lang->admin->menu; -$lang->mail->menu = $lang->admin->menu; - -/*菜單設置:分組設置。*/ -$lang->menugroup->release = 'product'; -$lang->menugroup->story = 'product'; -$lang->menugroup->productplan = 'product'; -$lang->menugroup->task = 'project'; -$lang->menugroup->build = 'project'; -$lang->menugroup->convert = 'admin'; -$lang->menugroup->upgrade = 'admin'; -$lang->menugroup->user = 'company'; -$lang->menugroup->group = 'company'; -$lang->menugroup->bug = 'qa'; -$lang->menugroup->testcase = 'qa'; -$lang->menugroup->testtask = 'qa'; -$lang->menugroup->people = 'company'; -$lang->menugroup->dept = 'company'; -$lang->menugroup->todo = 'my'; -$lang->menugroup->action = 'admin'; -$lang->menugroup->extension = 'admin'; -$lang->menugroup->editor = 'admin'; -$lang->menugroup->mail = 'admin'; - -/* 錯誤提示信息。*/ -$lang->error->companyNotFound = "您訪問的域名 %s 沒有對應的公司。"; -$lang->error->length = array("『%s』長度錯誤,應當為『%s』", "『%s』長度應當不超過『%s』,且不小於『%s』。"); -$lang->error->reg = "『%s』不符合格式,應當為:『%s』。"; -$lang->error->unique = "『%s』已經有『%s』這條記錄了。"; -$lang->error->gt = "『%s』應當大於『%s』。"; -$lang->error->notempty = "『%s』不能為空。"; -$lang->error->empty = "『%s』必須為空。"; -$lang->error->equal = "『%s』必須為『%s』。"; -$lang->error->int = array("『%s』應當是數字。", "『%s』應當介於『%s-%s』之間。"); -$lang->error->float = "『%s』應當是數字,可以是小數。"; -$lang->error->email = "『%s』應當為合法的EMAIL。"; -$lang->error->date = "『%s』應當為合法的日期。"; -$lang->error->account = "『%s』應當為合法的用戶名。"; -$lang->error->passwordsame = "兩次密碼應當相等。"; -$lang->error->passwordrule = "密碼應該符合規則,長度至少為六位。"; -$lang->error->accessDenied = '您沒有訪問權限'; - -/* 分頁信息。*/ -$lang->pager->noRecord = "暫時沒有記錄"; -$lang->pager->digest = "共%s條記錄,每頁 %s條,頁面:%s/%s "; -$lang->pager->first = "首頁"; -$lang->pager->pre = "上頁"; -$lang->pager->next = "下頁"; -$lang->pager->last = "末頁"; -$lang->pager->locate = "GO!"; - -$lang->zentaoSite = "官方網站"; -$lang->chinaScrum = "Scrum社區 "; -$lang->agileTraining = "培訓 "; -$lang->donate = "捐助禪道 "; -$lang->zentaoKeywords = "開源項目管理軟件,項目管理,項目管理軟件,pmp,pms,php框架,國產php框架,scrum工具,scrum管理工具,scrum管理軟件,敏捷項目管理,禪道"; -$lang->zentaoDESC = "禪道項目管理軟件(ZenTaoPMS)是一款國產的,基于LGPL協議,開源免費的項目管理軟件(工具、系統),同時也是一款scrum管理工具。 - 它集產品管理、項目管理、測試管理於一體,同時還包含了事務管理、組織管理等諸多功能,是中小型企業項目管理的首選。禪道項目管理軟件使用PHP + MySQL開發, -基于自主的PHP開發框架──ZenTaoPHP而成。第三方開發者或者企業可以非常方便的開發插件或者進行定製。禪道在手,項目無憂!"; - -/* 時間格式設置。*/ -define('DT_DATETIME1', 'Y-m-d H:i:s'); -define('DT_DATETIME2', 'y-m-d H:i'); -define('DT_MONTHTIME1', 'n/d H:i'); -define('DT_MONTHTIME2', 'n月d日 H:i'); -define('DT_DATE1', 'Y-m-d'); -define('DT_DATE2', 'Ymd'); -define('DT_DATE3', 'Y年m月d日'); -define('DT_DATE4', 'n月j日'); -define('DT_TIME1', 'H:i:s'); -define('DT_TIME2', 'H:i'); + + * @package ZenTaoPMS + * @version $Id: zh-tw.php 2600 2012-02-21 04:35:05Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +$lang->arrow = ' » '; +$lang->colon = '::'; +$lang->comma = ','; +$lang->dot = '。'; +$lang->at = ' 于 '; +$lang->downArrow = '↓'; + +$lang->ZenTaoPMS = '禪道管理'; +$lang->welcome = "歡迎使用『%s』{$lang->colon} {$lang->ZenTaoPMS}"; +$lang->myControl = "我的地盤"; +$lang->currentPos = '當前位置:'; +$lang->logout = '退出'; +$lang->login = '登錄'; +$lang->aboutZenTao = '關於'; +$lang->todayIs = '今天是%s,'; +$lang->runInfo = "
時間: %s 毫秒, 內存: %s KB, 查詢: %s.
"; + +$lang->reset = '重填'; +$lang->edit = '編輯'; +$lang->copy = '複製'; +$lang->delete = '刪除'; +$lang->close = '關閉'; +$lang->link = '關聯'; +$lang->unlink = '移除'; +$lang->import = '導入'; +$lang->export = '導出'; +$lang->setFileName = '檔案名:'; +$lang->activate = '激活'; +$lang->submitting = '稍候...'; +$lang->save = '保存'; +$lang->confirm = '確認'; +$lang->preview = '查看'; +$lang->goback = '返回'; +$lang->go = 'GO'; +$lang->more = '更多'; + +$lang->actions = '操作'; +$lang->comment = '備註'; +$lang->history = '歷史記錄'; +$lang->attatch = '附件'; +$lang->reverse = '[切換順序]'; +$lang->switchDisplay= '[切換顯示]'; +$lang->switchHelp = '切換幫助'; +$lang->addFiles = '上傳了附件 '; +$lang->files = '附件 '; +$lang->unfold = '+'; +$lang->fold = '-'; + +$lang->selectAll = '全選'; +$lang->notFound = '抱歉,您訪問的對象並不存在!'; +$lang->showAll = '++ 全部顯示 ++'; +$lang->hideClosed = '-- 隱藏已結束 --'; + +$lang->future = '未來'; +$lang->year = '年'; +$lang->workingHour = '工時'; + +$lang->idAB = 'ID'; +$lang->priAB = 'P'; +$lang->statusAB = '狀態'; +$lang->openedByAB = '創建'; +$lang->assignedToAB = '指派'; +$lang->typeAB = '類型'; + +$lang->common->common = '公有模組'; + +/* 主導航菜單。*/ +$lang->menu->my = '我的地盤|my|index'; +$lang->menu->product = '產品視圖|product|index'; +$lang->menu->project = '項目視圖|project|index'; +$lang->menu->qa = '測試視圖|qa|index'; +$lang->menu->doc = '文檔視圖|doc|index'; +$lang->menu->company = '組織視圖|company|index'; +$lang->menu->admin = '後台管理|admin|index'; + +/* 查詢條中可以選擇的對象列表。*/ +$lang->searchObjects['bug'] = 'B:Bug'; +$lang->searchObjects['story'] = 'S:需求'; +$lang->searchObjects['task'] = 'T:任務'; +$lang->searchObjects['testcase'] = 'C:用例'; +$lang->searchObjects['project'] = 'P:項目'; +$lang->searchObjects['product'] = 'P:產品'; +$lang->searchObjects['user'] = 'U:用戶'; +$lang->searchObjects['build'] = 'B:Build'; +$lang->searchObjects['release'] = 'R:發佈'; +$lang->searchObjects['productplan'] = 'P:產品計劃'; +$lang->searchObjects['testtask'] = 'T:測試任務'; +$lang->searchObjects['doc'] = 'D:文檔'; +$lang->searchTips = '輸入編號'; + +/* 導出檔案的類型列表。*/ +$lang->exportFileTypeList['csv'] = 'csv'; +$lang->exportFileTypeList['xml'] = 'xml'; +$lang->exportFileTypeList['html'] = 'html'; + +/* 風格列表。*/ +$lang->themes['default'] = '預設'; +$lang->themes['green'] = '綠色'; +$lang->themes['red'] = '紅色'; +$lang->themes['classblue'] = '經典藍'; + +/* 首頁菜單設置。*/ +$lang->index->menu->product = '瀏覽產品|product|browse'; +$lang->index->menu->project = '瀏覽項目|project|browse'; + +/* 我的地盤菜單設置。*/ +$lang->my->menu->account = '%s' . $lang->arrow; +$lang->my->menu->index = '首頁|my|index'; +$lang->my->menu->todo = array('link' => '我的TODO|my|todo|', 'subModule' => 'todo'); +$lang->my->menu->task = '我的任務|my|task|'; +$lang->my->menu->bug = '我的Bug|my|bug|'; +$lang->my->menu->testtask = '我的測試|my|testtask|'; +$lang->my->menu->story = '我的需求|my|story|'; +$lang->my->menu->myProject = '我的項目|my|project|'; +$lang->my->menu->dynamic = '我的動態|my|dynamic|'; +$lang->my->menu->profile = array('link' => '我的檔案|my|profile|', 'alias' => 'editprofile'); +$lang->todo->menu = $lang->my->menu; + +/* 產品視圖設置。*/ +$lang->product->menu->list = '%s'; +$lang->product->menu->story = array('link' => '需求|product|browse|productID=%s', 'subModule' => 'story'); +$lang->product->menu->dynamic = '動態|product|dynamic|productID=%s'; +$lang->product->menu->plan = array('link' => '計劃|productplan|browse|productID=%s', 'subModule' => 'productplan'); +$lang->product->menu->release = array('link' => '發佈|release|browse|productID=%s', 'subModule' => 'release'); +$lang->product->menu->roadmap = '路線圖|product|roadmap|productID=%s'; +$lang->product->menu->doc = array('link' => '文檔|product|doc|productID=%s', 'subModule' => 'doc'); +$lang->product->menu->view = '概況|product|view|productID=%s'; +$lang->product->menu->edit = '編輯|product|edit|productID=%s'; +$lang->product->menu->delete = array('link' => '刪除|product|delete|productID=%s', 'target' => 'hiddenwin'); +$lang->product->menu->module = '模組|tree|browse|productID=%s&view=story'; +$lang->product->menu->order = '排序|product|order|productID=%s'; +$lang->product->menu->create = array('link' => '新增產品|product|create', 'float' => 'right'); +$lang->product->menu->project = array('link' => '項目列表|product|project|status=all&productID=%s', 'float' => 'right'); +$lang->product->menu->all = array('link' => '所有產品|product|index|locate=false', 'float' => 'right'); +$lang->story->menu = $lang->product->menu; +$lang->productplan->menu = $lang->product->menu; +$lang->release->menu = $lang->product->menu; + +/* 項目視圖菜單設置。*/ +$lang->project->menu->list = '%s'; +$lang->project->menu->task = array('link' => '任務|project|task|projectID=%s', 'subModule' => 'task', 'alias' => 'grouptask,importtask'); +$lang->project->menu->story = array('link' => '需求|project|story|projectID=%s'); +$lang->project->menu->bug = 'Bug|project|bug|projectID=%s'; +$lang->project->menu->dynamic = '動態|project|dynamic|projectID=%s'; +$lang->project->menu->build = array('link' => 'Build|project|build|projectID=%s', 'subModule' => 'build'); +$lang->project->menu->testtask = '測試申請|project|testtask|projectID=%s'; +$lang->project->menu->burn = '燃盡圖|project|burn|projectID=%s'; +$lang->project->menu->team = array('link' => '團隊|project|team|projectID=%s', 'alias' => 'managemembers'); +$lang->project->menu->doc = array('link' => '文檔|project|doc|porjectID=%s', 'subModule' => 'doc'); +$lang->project->menu->product = '產品|project|manageproducts|projectID=%s'; +$lang->project->menu->linkstory = array('link' => '關聯需求|project|linkstory|projectID=%s'); +$lang->project->menu->view = '概況|project|view|projectID=%s'; +$lang->project->menu->edit = '編輯|project|edit|projectID=%s'; +$lang->project->menu->delete = array('link' => '刪除|project|delete|projectID=%s', 'target' => 'hiddenwin'); +$lang->project->menu->order = '排序|project|order|projectID=%s'; +$lang->project->menu->create = array('link' => '新增項目|project|create', 'float' => 'right'); +$lang->project->menu->toCopy = array('link' => '複製項目|project|create|projectID=©ProjectID=%s', 'float' => 'right'); +$lang->project->menu->all = array('link' => '所有項目|project|index|locate=false', 'float' => 'right'); +$lang->task->menu = $lang->project->menu; +$lang->build->menu = $lang->project->menu; + +/* QA視圖菜單設置。*/ +$lang->bug->menu->product = '%s'; +$lang->bug->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s', 'alias' => 'view,create,edit,resolve,close,activate,report', 'subModule' => 'tree'); +$lang->bug->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,edit'); +$lang->bug->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s'); + +$lang->testcase->menu->product = '%s'; +$lang->testcase->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); +$lang->testcase->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s', 'alias' => 'view,create,batchcreate,edit', 'subModule' => 'tree'); +$lang->testcase->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s'); + +$lang->testtask->menu->product = '%s'; +$lang->testtask->menu->bug = array('link' => '缺陷管理|bug|browse|productID=%s'); +$lang->testtask->menu->testcase = array('link' => '用例管理|testcase|browse|productID=%s'); +$lang->testtask->menu->testtask = array('link' => '測試任務|testtask|browse|productID=%s', 'alias' => 'view,create,edit,linkcase,cases'); + +/* 文檔視圖菜單設置。*/ +$lang->doc->menu->list = '%s'; +$lang->doc->menu->browse = array('link' => '文檔列表|doc|browse|libID=%s'); +$lang->doc->menu->edit = '編輯文檔庫|doc|editLib|libID=%s'; +$lang->doc->menu->module = '維護模組|tree|browse|libID=%s&viewType=doc'; +$lang->doc->menu->delete = array('link' => '刪除文檔庫|doc|deleteLib|libID=%s', 'target' => 'hiddenwin'); +$lang->doc->menu->create = array('link' => '新增文檔庫|doc|createLib', 'float' => 'right'); + +/* 組織結構視圖菜單設置。*/ +$lang->company->menu->name = '%s' . $lang->arrow; +$lang->company->menu->browseUser = array('link' => '用戶列表|company|browse', 'subModule' => 'user'); +$lang->company->menu->dept = array('link' => '部門維護|dept|browse', 'subModule' => 'dept'); +$lang->company->menu->browseGroup = array('link' => '權限分組|group|browse', 'subModule' => 'group'); +$lang->company->menu->edit = array('link' => '公司管理|company|edit'); +$lang->company->menu->dynamic = '組織動態|company|dynamic|'; +$lang->company->menu->addGroup = array('link' => '添加分組|group|create', 'float' => 'right'); +$lang->company->menu->addUser = array('link' => '添加用戶|user|create|dept=%s', 'subModule' => 'user', 'float' => 'right'); +$lang->dept->menu = $lang->company->menu; +$lang->group->menu = $lang->company->menu; + +/* 用戶信息菜單設置。*/ +$lang->user->menu->account = '%s' . $lang->arrow; +$lang->user->menu->todo = array('link' => 'TODO列表|user|todo|account=%s', 'subModule' => 'todo'); +$lang->user->menu->task = '任務列表|user|task|account=%s'; +$lang->user->menu->bug = 'Bug列表|user|bug|account=%s'; +$lang->user->menu->dynamic = '用戶動態|user|dynamic|type=today&account=%s'; +$lang->user->menu->projectList = '項目列表|user|project|account=%s'; +$lang->user->menu->profile = array('link' => '用戶信息|user|profile|account=%s', 'alias' => 'edit'); +$lang->user->menu->browse = array('link' => '用戶管理|company|browse|', 'float' => 'right'); + +/* 後台管理菜單設置。*/ +$lang->admin->menu->index = array('link' => '首頁|admin|index', 'subModule' => 'admin'); +$lang->admin->menu->extension = array('link' => '插件管理|extension|browse', 'subModule' => 'extension'); +$lang->admin->menu->editor = array('link' => '擴展編輯器|editor|index', 'subModule' => 'editor'); +$lang->admin->menu->mail = array('link' => 'Email配置|mail|set', 'subModule' => 'mail'); +$lang->admin->menu->convert = array('link' => '從其他系統導入|convert|index', 'subModule' => 'convert'); +$lang->admin->menu->trashes = array('link' => '資源回收筒|action|trash', 'subModule' => 'action'); +$lang->convert->menu = $lang->admin->menu; +$lang->upgrade->menu = $lang->admin->menu; +$lang->action->menu = $lang->admin->menu; +$lang->extension->menu = $lang->admin->menu; +$lang->editor->menu = $lang->admin->menu; +$lang->mail->menu = $lang->admin->menu; + +/*菜單設置:分組設置。*/ +$lang->menugroup->release = 'product'; +$lang->menugroup->story = 'product'; +$lang->menugroup->productplan = 'product'; +$lang->menugroup->task = 'project'; +$lang->menugroup->build = 'project'; +$lang->menugroup->convert = 'admin'; +$lang->menugroup->upgrade = 'admin'; +$lang->menugroup->user = 'company'; +$lang->menugroup->group = 'company'; +$lang->menugroup->bug = 'qa'; +$lang->menugroup->testcase = 'qa'; +$lang->menugroup->testtask = 'qa'; +$lang->menugroup->people = 'company'; +$lang->menugroup->dept = 'company'; +$lang->menugroup->todo = 'my'; +$lang->menugroup->action = 'admin'; +$lang->menugroup->extension = 'admin'; +$lang->menugroup->editor = 'admin'; +$lang->menugroup->mail = 'admin'; + +/* 錯誤提示信息。*/ +$lang->error->companyNotFound = "您訪問的域名 %s 沒有對應的公司。"; +$lang->error->length = array("『%s』長度錯誤,應當為『%s』", "『%s』長度應當不超過『%s』,且不小於『%s』。"); +$lang->error->reg = "『%s』不符合格式,應當為:『%s』。"; +$lang->error->unique = "『%s』已經有『%s』這條記錄了。"; +$lang->error->gt = "『%s』應當大於『%s』。"; +$lang->error->notempty = "『%s』不能為空。"; +$lang->error->empty = "『%s』必須為空。"; +$lang->error->equal = "『%s』必須為『%s』。"; +$lang->error->int = array("『%s』應當是數字。", "『%s』應當介於『%s-%s』之間。"); +$lang->error->float = "『%s』應當是數字,可以是小數。"; +$lang->error->email = "『%s』應當為合法的EMAIL。"; +$lang->error->date = "『%s』應當為合法的日期。"; +$lang->error->account = "『%s』應當為合法的用戶名。"; +$lang->error->passwordsame = "兩次密碼應當相等。"; +$lang->error->passwordrule = "密碼應該符合規則,長度至少為六位。"; +$lang->error->accessDenied = '您沒有訪問權限'; + +/* 分頁信息。*/ +$lang->pager->noRecord = "暫時沒有記錄"; +$lang->pager->digest = "共%s條記錄,每頁 %s條,頁面:%s/%s "; +$lang->pager->first = "首頁"; +$lang->pager->pre = "上頁"; +$lang->pager->next = "下頁"; +$lang->pager->last = "末頁"; +$lang->pager->locate = "GO!"; + +$lang->zentaoSite = "官方網站"; +$lang->chinaScrum = "Scrum社區 "; +$lang->agileTraining = "培訓 "; +$lang->donate = "捐助禪道 "; +$lang->zentaoKeywords = "開源項目管理軟件,項目管理,項目管理軟件,pmp,pms,php框架,國產php框架,scrum工具,scrum管理工具,scrum管理軟件,敏捷項目管理,禪道"; +$lang->zentaoDESC = "禪道項目管理軟件(ZenTaoPMS)是一款國產的,基于LGPL協議,開源免費的項目管理軟件(工具、系統),同時也是一款scrum管理工具。 + 它集產品管理、項目管理、測試管理於一體,同時還包含了事務管理、組織管理等諸多功能,是中小型企業項目管理的首選。禪道項目管理軟件使用PHP + MySQL開發, +基于自主的PHP開發框架──ZenTaoPHP而成。第三方開發者或者企業可以非常方便的開發插件或者進行定製。禪道在手,項目無憂!"; + +/* 時間格式設置。*/ +define('DT_DATETIME1', 'Y-m-d H:i:s'); +define('DT_DATETIME2', 'y-m-d H:i'); +define('DT_MONTHTIME1', 'n/d H:i'); +define('DT_MONTHTIME2', 'n月d日 H:i'); +define('DT_DATE1', 'Y-m-d'); +define('DT_DATE2', 'Ymd'); +define('DT_DATE3', 'Y年m月d日'); +define('DT_DATE4', 'n月j日'); +define('DT_TIME1', 'H:i:s'); +define('DT_TIME2', 'H:i'); diff --git a/module/common/model.php b/module/common/model.php index d2a72b5751..bcd6472066 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -1,366 +1,366 @@ - - * @package common - * @version $Id$ - * @link http://www.zentao.net - */ -class commonModel extends model -{ - /** - * Start the session. - * - * @access public - * @return void - */ - public function startSession() - { - session_name($this->config->sessionVar); - if(isset($_GET[$this->config->sessionVar])) session_id($_GET[$this->config->sessionVar]); - session_start(); - } - - /** - * Set the header info. - * - * @access public - * @return void - */ - public function sendHeader() - { - header("Content-Type: text/html; Language={$this->config->encoding}"); - header("Cache-control: private"); - } - - /** - * Set the commpany. - * - * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default. - * After get the company, save it to session. - * @access public - * @return void - */ - public function setCompany() - { - $httpHost = $this->server->http_host; - if(strpos($httpHost, ":")) - { - $httpHost = explode(":", $httpHost); - $httpHost = $httpHost[0]; - } - - if($this->session->company and $this->session->company->pms == $httpHost) - { - $this->app->company = $this->session->company; - } - else - { - $company = $this->loadModel('company')->getByDomain(); - if(!$company and isset($this->config->default->domain)) $company = $this->company->getByDomain($this->config->default->domain); - if(!$company) $company = $this->company->getFirst(); - if(!$company) $this->app->error(sprintf($this->lang->error->companyNotFound, $httpHost), __FILE__, __LINE__, $exit = true); - $this->session->set('company', $company); - $this->app->company = $company; - } - } - - /** - * Set the user info. - * - * @access public - * @return void - */ - public function setUser() - { - if($this->session->user) - { - $this->app->user = $this->session->user; - } - elseif($this->app->company->guest) - { - $user = new stdClass(); - $user->id = 0; - $user->account = 'guest'; - $user->realname = 'guest'; - $user->rights = $this->loadModel('user')->authorize('guest'); - $this->session->set('user', $user); - $this->app->user = $this->session->user; - } - } - - /** - * Juage a method of one module is open or not? - * - * @param string $module - * @param string $method - * @access public - * @return bool - */ - public function isOpenMethod($module, $method) - { - if($module == 'user' and strpos('login|logout|deny', $method) !== false) return true; - if($module == 'api' and $method == 'getsessionid') return true; - if($module == 'misc' and $method == 'about') return true; - if($module == 'help' and $method == 'field') return true; - return false; - } - - /** - * Deny access. - * - * @access public - * @return void - */ - public function deny($module, $method) - { - $vars = "module=$module&method=$method"; - if(isset($this->server->http_referer)) - { - $referer = helper::safe64Encode($this->server->http_referer); - $vars .= "&referer=$referer"; - } - $denyLink = helper::createLink('user', 'deny', $vars); - - /* Fix the bug of IE: use js locate, can't get the referer. */ - if(strpos($this->server->http_user_agent, 'MSIE') !== false) - { - echo ""; - echo ""; - } - else - { - echo js::locate($denyLink); - } - exit; - } - - /** - * Get the run info. - * - * @param mixed $startTime the start time of this execution - * @access public - * @return array the run info array. - */ - public function getRunInfo($startTime) - { - $info['timeUsed'] = round(getTime() - $startTime, 4) * 1000; - $info['memory'] = round(memory_get_peak_usage() / 1024, 1); - $info['querys'] = count(dao::$querys); - return $info; - } - - /** - * Print top bar. - * - * @static - * @access public - * @return void - */ - public static function printTopBar() - { - global $lang, $app; - - printf($lang->todayIs, date(DT_DATE3)); - if(isset($app->user)) echo $app->user->realname . ' '; - if(isset($app->user) and $app->user->account != 'guest') - { - echo html::a(helper::createLink('my', 'index'), $lang->myControl); - echo html::a(helper::createLink('user', 'logout'), $lang->logout); - } - else - { - echo html::a(helper::createLink('user', 'login'), $lang->login); - } - echo html::a(helper::createLink('misc', 'about'), $lang->aboutZenTao, '', "class='about'"); - echo $lang->agileTraining; - echo $lang->donate; - } - - /** - * Print the main menu. - * - * @param string $moduleName - * @static - * @access public - * @return void - */ - public static function printMainmenu($moduleName) - { - global $app, $lang; - echo "
    \n"; - - /* Set the main main menu. */ - $mainMenu = $moduleName; - if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName; - - /* Print all main menus. */ - foreach($lang->menu as $menuKey => $menu) - { - $active = $menuKey == $mainMenu ? "class='active'" : ''; - list($menuLabel, $module, $method) = explode('|', $menu); - - if(common::hasPriv($module, $method)) - { - $link = helper::createLink($module, $method); - echo "
  • $menuLabel
  • \n"; - } - } - - } - - /** - * Print the search box. - * - * @static - * @access public - * @return void - */ - public static function printSearchBox() - { - global $app, $lang; - $moduleName = $app->getModuleName(); - $methodName = $app->getMethodName(); - $searchObject = $moduleName; - - if($moduleName == 'product') - { - if($methodName == 'browse') $searchObject = 'story'; - } - elseif($moduleName == 'project') - { - if(strpos('task|story|bug|build', $methodName) !== false) $searchObject = $methodName; - } - elseif($moduleName == 'my' or $moduleName == 'user') - { - $searchObject = $methodName; - } - - echo ""; - echo "
\n"; - } - - /** - * Print the module menu. - * - * @param string $moduleName - * @static - * @access public - * @return void - */ - public static function printModuleMenu($moduleName) - { - global $lang, $app; - - if(!isset($lang->$moduleName->menu)) {echo "
    "; return;} - - /* Get the sub menus of the module, and get current module and method. */ - $submenus = $lang->$moduleName->menu; - $currentModule = $app->getModuleName(); - $currentMethod = $app->getMethodName(); - - /* The beginning of the menu. */ - echo "
      \n"; - - /* Cycling to print every sub menus. */ - foreach($submenus as $subMenuKey => $submenu) - { - /* Init the these vars. */ - $link = $submenu; - $subModule = ''; - $alias = ''; - $float = ''; - $active = ''; - $target = ''; - - if(is_array($submenu)) extract($submenu); // If the sub menu is an array, extract it. - - /* Print the menu. */ - if(strpos($link, '|') === false) - { - echo "
    • $link
    • \n"; - } - else - { - $link = explode('|', $link); - list($label, $module, $method) = $link; - $vars = isset($link[3]) ? $link[3] : ''; - if(common::hasPriv($module, $method)) - { - /* Is the currentModule active? */ - if($currentModule == $subModule) $active = 'active'; - if($module == $currentModule and ($method == $currentMethod or strpos($alias, $currentMethod) !== false)) $active = 'active'; - echo "
    • " . html::a(helper::createLink($module, $method, $vars), $label, $target, "id=submenu$subMenuKey") . "
    • \n"; - } - } - } - echo "
    \n"; - } - - /** - * Print the bread menu. - * - * @param string $moduleName - * @param string $position - * @static - * @access public - * @return void - */ - public static function printBreadMenu($moduleName, $position) - { - global $lang; - $mainMenu = $moduleName; - if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName; - echo html::a(helper::createLink('my', 'index'), $lang->ZenTaoPMS) . $lang->arrow; - if($moduleName != 'index') - { - list($menuLabel, $module, $method) = explode('|', $lang->menu->$mainMenu); - echo html::a(helper::createLink($module, $method), $menuLabel); - } - else - { - echo $lang->index->common; - } - if(empty($position)) return; - echo $lang->arrow; - foreach($position as $key => $link) - { - echo $link; - if(isset($position[$key + 1])) echo $lang->arrow; - } - } - - - /** - * Diff two string. (see phpt) - * - * @param string $text1 - * @param string $text2 - * @static - * @access public - * @return string - */ - public static function diff($text1, $text2) - { - $text1 = str_replace(' ', '', trim($text1)); - $text2 = str_replace(' ', '', trim($text2)); - $w = explode("\n", $text1); - $o = explode("\n", $text2); - $w1 = array_diff_assoc($w,$o); - $o1 = array_diff_assoc($o,$w); - $w2 = array(); - $o2 = array(); - foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1) . "" . trim($val) . ""; - foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1) . "" . trim($val) . ""; - $diff = array_merge($w2, $o2); - ksort($diff); - return implode("\n", $diff); - } -} + + * @package common + * @version $Id$ + * @link http://www.zentao.net + */ +class commonModel extends model +{ + /** + * Start the session. + * + * @access public + * @return void + */ + public function startSession() + { + session_name($this->config->sessionVar); + if(isset($_GET[$this->config->sessionVar])) session_id($_GET[$this->config->sessionVar]); + session_start(); + } + + /** + * Set the header info. + * + * @access public + * @return void + */ + public function sendHeader() + { + header("Content-Type: text/html; Language={$this->config->encoding}"); + header("Cache-control: private"); + } + + /** + * Set the commpany. + * + * First, search company by the http host. If not found, search by the default domain. Last, use the first as the default. + * After get the company, save it to session. + * @access public + * @return void + */ + public function setCompany() + { + $httpHost = $this->server->http_host; + if(strpos($httpHost, ":")) + { + $httpHost = explode(":", $httpHost); + $httpHost = $httpHost[0]; + } + + if($this->session->company and $this->session->company->pms == $httpHost) + { + $this->app->company = $this->session->company; + } + else + { + $company = $this->loadModel('company')->getByDomain(); + if(!$company and isset($this->config->default->domain)) $company = $this->company->getByDomain($this->config->default->domain); + if(!$company) $company = $this->company->getFirst(); + if(!$company) $this->app->error(sprintf($this->lang->error->companyNotFound, $httpHost), __FILE__, __LINE__, $exit = true); + $this->session->set('company', $company); + $this->app->company = $company; + } + } + + /** + * Set the user info. + * + * @access public + * @return void + */ + public function setUser() + { + if($this->session->user) + { + $this->app->user = $this->session->user; + } + elseif($this->app->company->guest) + { + $user = new stdClass(); + $user->id = 0; + $user->account = 'guest'; + $user->realname = 'guest'; + $user->rights = $this->loadModel('user')->authorize('guest'); + $this->session->set('user', $user); + $this->app->user = $this->session->user; + } + } + + /** + * Juage a method of one module is open or not? + * + * @param string $module + * @param string $method + * @access public + * @return bool + */ + public function isOpenMethod($module, $method) + { + if($module == 'user' and strpos('login|logout|deny', $method) !== false) return true; + if($module == 'api' and $method == 'getsessionid') return true; + if($module == 'misc' and $method == 'about') return true; + if($module == 'help' and $method == 'field') return true; + return false; + } + + /** + * Deny access. + * + * @access public + * @return void + */ + public function deny($module, $method) + { + $vars = "module=$module&method=$method"; + if(isset($this->server->http_referer)) + { + $referer = helper::safe64Encode($this->server->http_referer); + $vars .= "&referer=$referer"; + } + $denyLink = helper::createLink('user', 'deny', $vars); + + /* Fix the bug of IE: use js locate, can't get the referer. */ + if(strpos($this->server->http_user_agent, 'MSIE') !== false) + { + echo ""; + echo ""; + } + else + { + echo js::locate($denyLink); + } + exit; + } + + /** + * Get the run info. + * + * @param mixed $startTime the start time of this execution + * @access public + * @return array the run info array. + */ + public function getRunInfo($startTime) + { + $info['timeUsed'] = round(getTime() - $startTime, 4) * 1000; + $info['memory'] = round(memory_get_peak_usage() / 1024, 1); + $info['querys'] = count(dao::$querys); + return $info; + } + + /** + * Print top bar. + * + * @static + * @access public + * @return void + */ + public static function printTopBar() + { + global $lang, $app; + + printf($lang->todayIs, date(DT_DATE3)); + if(isset($app->user)) echo $app->user->realname . ' '; + if(isset($app->user) and $app->user->account != 'guest') + { + echo html::a(helper::createLink('my', 'index'), $lang->myControl); + echo html::a(helper::createLink('user', 'logout'), $lang->logout); + } + else + { + echo html::a(helper::createLink('user', 'login'), $lang->login); + } + echo html::a(helper::createLink('misc', 'about'), $lang->aboutZenTao, '', "class='about'"); + echo $lang->agileTraining; + echo $lang->donate; + } + + /** + * Print the main menu. + * + * @param string $moduleName + * @static + * @access public + * @return void + */ + public static function printMainmenu($moduleName) + { + global $app, $lang; + echo "
      \n"; + + /* Set the main main menu. */ + $mainMenu = $moduleName; + if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName; + + /* Print all main menus. */ + foreach($lang->menu as $menuKey => $menu) + { + $active = $menuKey == $mainMenu ? "class='active'" : ''; + list($menuLabel, $module, $method) = explode('|', $menu); + + if(common::hasPriv($module, $method)) + { + $link = helper::createLink($module, $method); + echo "
    • $menuLabel
    • \n"; + } + } + + } + + /** + * Print the search box. + * + * @static + * @access public + * @return void + */ + public static function printSearchBox() + { + global $app, $lang; + $moduleName = $app->getModuleName(); + $methodName = $app->getMethodName(); + $searchObject = $moduleName; + + if($moduleName == 'product') + { + if($methodName == 'browse') $searchObject = 'story'; + } + elseif($moduleName == 'project') + { + if(strpos('task|story|bug|build', $methodName) !== false) $searchObject = $methodName; + } + elseif($moduleName == 'my' or $moduleName == 'user') + { + $searchObject = $methodName; + } + + echo ""; + echo "
    \n"; + } + + /** + * Print the module menu. + * + * @param string $moduleName + * @static + * @access public + * @return void + */ + public static function printModuleMenu($moduleName) + { + global $lang, $app; + + if(!isset($lang->$moduleName->menu)) {echo "
      "; return;} + + /* Get the sub menus of the module, and get current module and method. */ + $submenus = $lang->$moduleName->menu; + $currentModule = $app->getModuleName(); + $currentMethod = $app->getMethodName(); + + /* The beginning of the menu. */ + echo "
        \n"; + + /* Cycling to print every sub menus. */ + foreach($submenus as $subMenuKey => $submenu) + { + /* Init the these vars. */ + $link = $submenu; + $subModule = ''; + $alias = ''; + $float = ''; + $active = ''; + $target = ''; + + if(is_array($submenu)) extract($submenu); // If the sub menu is an array, extract it. + + /* Print the menu. */ + if(strpos($link, '|') === false) + { + echo "
      • $link
      • \n"; + } + else + { + $link = explode('|', $link); + list($label, $module, $method) = $link; + $vars = isset($link[3]) ? $link[3] : ''; + if(common::hasPriv($module, $method)) + { + /* Is the currentModule active? */ + if($currentModule == $subModule) $active = 'active'; + if($module == $currentModule and ($method == $currentMethod or strpos($alias, $currentMethod) !== false)) $active = 'active'; + echo "
      • " . html::a(helper::createLink($module, $method, $vars), $label, $target, "id=submenu$subMenuKey") . "
      • \n"; + } + } + } + echo "
      \n"; + } + + /** + * Print the bread menu. + * + * @param string $moduleName + * @param string $position + * @static + * @access public + * @return void + */ + public static function printBreadMenu($moduleName, $position) + { + global $lang; + $mainMenu = $moduleName; + if(isset($lang->menugroup->$moduleName)) $mainMenu = $lang->menugroup->$moduleName; + echo html::a(helper::createLink('my', 'index'), $lang->ZenTaoPMS) . $lang->arrow; + if($moduleName != 'index') + { + list($menuLabel, $module, $method) = explode('|', $lang->menu->$mainMenu); + echo html::a(helper::createLink($module, $method), $menuLabel); + } + else + { + echo $lang->index->common; + } + if(empty($position)) return; + echo $lang->arrow; + foreach($position as $key => $link) + { + echo $link; + if(isset($position[$key + 1])) echo $lang->arrow; + } + } + + + /** + * Diff two string. (see phpt) + * + * @param string $text1 + * @param string $text2 + * @static + * @access public + * @return string + */ + public static function diff($text1, $text2) + { + $text1 = str_replace(' ', '', trim($text1)); + $text2 = str_replace(' ', '', trim($text2)); + $w = explode("\n", $text1); + $o = explode("\n", $text2); + $w1 = array_diff_assoc($w,$o); + $o1 = array_diff_assoc($o,$w); + $w2 = array(); + $o2 = array(); + foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1) . "" . trim($val) . ""; + foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1) . "" . trim($val) . ""; + $diff = array_merge($w2, $o2); + ksort($diff); + return implode("\n", $diff); + } +} diff --git a/module/common/view/footer.html.php b/module/common/view/footer.html.php index 948a5baec7..a00673f1bf 100644 --- a/module/common/view/footer.html.php +++ b/module/common/view/footer.html.php @@ -1,27 +1,27 @@ - -getExtViewFile(__FILE__)){include $extView; return helper::cd();}?> -
      - - - - - - + +getExtViewFile(__FILE__)){include $extView; return helper::cd();}?> +
      + + + + + + diff --git a/module/common/view/footer.lite.html.php b/module/common/view/footer.lite.html.php index fc581f53b9..8008f62818 100644 --- a/module/common/view/footer.lite.html.php +++ b/module/common/view/footer.lite.html.php @@ -1,9 +1,9 @@ - -getExtViewFile(__FILE__)){include $extView; return helper::cd();}?> - - - - + +getExtViewFile(__FILE__)){include $extView; return helper::cd();}?> + + + + diff --git a/module/company/control.php b/module/company/control.php index 95a21cc407..b58c9a3872 100644 --- a/module/company/control.php +++ b/module/company/control.php @@ -1,236 +1,236 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -class company extends control -{ - /** - * Construct function, load dept and user models auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('dept'); - $this->app->loadLang('user'); - $this->company->setMenu(); - } - - /** - * Index page, header to browse. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('company', 'browse')); - } - - /** - * Browse departments and users of a company. - * - * @param int $deptID - * @access public - * @return void - */ - public function browse($deptID = 0) - { - $this->lang->set('menugroup.company', 'company'); - $childDeptIds = $this->dept->getAllChildID($deptID); - - $this->company->setMenu($deptID); - - $header['title'] = $this->lang->company->index . $this->lang->colon . $this->lang->dept->common; - $position[] = $this->lang->dept->common; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->users = $this->dept->getUsers($childDeptIds); - $this->view->deptTree = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptModel', 'createMemberLink')); - $this->view->parentDepts = $this->dept->getParents($deptID); - $this->view->deptID = $deptID; - - $this->display(); - } - - /** - * Create a company. - * - * @access public - * @return void - */ - public function create() - { - if(!empty($_POST)) - { - $this->company->create(); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('admin', 'browsecompany'), 'parent')); - } - - $this->lang->set('menugroup.company', 'admin'); - $this->lang->company->menu = $this->lang->admin->menu; - - $header['title'] = $this->lang->admin->common . $this->lang->colon . $this->lang->company->create; - $position[] = html::a($this->createLink('admin', 'browsecompany'), $this->lang->admin->company); - $position[] = $this->lang->company->create; - $this->view->header = $header; - $this->view->position = $position; - - $this->display(); - } - - /** - * Edit a company. - * - * @access public - * @return void - */ - public function edit() - { - if(!empty($_POST)) - { - $this->company->update(); - if(dao::isError()) die(js::error(dao::getError())); - die(js::alert($this->lang->company->successSaved)); - } - - $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->company->edit; - $position[] = $this->lang->company->edit; - $this->view->header = $header; - $this->view->position = $position; - $this->view->company = $this->company->getById($this->app->company->id); - - $this->display(); - } - - /** - * Delete a company. - * - * @param int $companyID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($companyID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->company->confirmDelete, $this->createLink('company', 'delete', "companyID=$companyID&confirm=yes")); - exit; - } - else - { - $this->company->delete($companyID); - echo js::locate($this->createLink('admin', 'browseCompany'), 'parent'); - exit; - } - } - - /** - * Company dynamic. - * - * @param string $browseType - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function dynamic($browseType = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - $this->app->loadLang('user'); - $this->app->loadLang('project'); - $this->loadModel('action'); - - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - /* Set the pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - - /* Set the user and type. */ - $account = $browseType == 'account' ? $param : 'all'; - $product = $browseType == 'product' ? $param : 'all'; - $project = $browseType == 'project' ? $param : 'all'; - $period = ($browseType == 'account' or $browseType == 'product' or $browseType == 'project') ? 'all' : $browseType; - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Get products' list.*/ - $products = $this->loadModel('product')->getPairs(); - $products = array($this->lang->product->select) + $products; - $this->view->products = $products; - - /* Get projects' list.*/ - $projects = $this->loadModel('project')->getPairs(); - $projects = array($this->lang->project->select) + $projects; - $this->view->projects = $projects; - - /* Get users.*/ - $users = $this->loadModel('user')->getPairs('nodeleted|noletter|noclosed'); - $users[''] = $this->lang->user->select; - $this->view->users = $users; - - /* The header and position. */ - $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic; - $this->view->position[] = $this->lang->company->dynamic; - - /* Get actions. */ - if($browseType != 'bysearch') - { - $actions = $this->action->getDynamic($account, $period, $orderBy, $pager, $product, $project); - } - else - { - $actions = $this->action->getDynamicBySearch($products, $projects, $queryID, $orderBy, $pager); - } - - /* Build search form. */ - $projects[0] = ''; - $products[0] = ''; - $users[''] = ''; - ksort($projects); - ksort($products); - $projects['all'] = $this->lang->project->allProject; - $products['all'] = $this->lang->product->allProduct; - $this->config->company->dynamic->search['actionURL'] = $this->createLink('company', 'dynamic', "browseType=bysearch¶m=myQueryID"); - $this->config->company->dynamic->search['queryID'] = $queryID; - $this->config->company->dynamic->search['params']['project']['values'] = $projects; - $this->config->company->dynamic->search['params']['product']['values'] = $products; - $this->config->company->dynamic->search['params']['actor']['values'] = $users; - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->company->dynamic->search); - - /* Assign. */ - $this->view->browseType = $browseType; - $this->view->account = $account; - $this->view->product = $product; - $this->view->project = $project; - $this->view->queryID = $queryID; - $this->view->actions = $actions; - $this->display(); - } -} + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +class company extends control +{ + /** + * Construct function, load dept and user models auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('dept'); + $this->app->loadLang('user'); + $this->company->setMenu(); + } + + /** + * Index page, header to browse. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('company', 'browse')); + } + + /** + * Browse departments and users of a company. + * + * @param int $deptID + * @access public + * @return void + */ + public function browse($deptID = 0) + { + $this->lang->set('menugroup.company', 'company'); + $childDeptIds = $this->dept->getAllChildID($deptID); + + $this->company->setMenu($deptID); + + $header['title'] = $this->lang->company->index . $this->lang->colon . $this->lang->dept->common; + $position[] = $this->lang->dept->common; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->users = $this->dept->getUsers($childDeptIds); + $this->view->deptTree = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptModel', 'createMemberLink')); + $this->view->parentDepts = $this->dept->getParents($deptID); + $this->view->deptID = $deptID; + + $this->display(); + } + + /** + * Create a company. + * + * @access public + * @return void + */ + public function create() + { + if(!empty($_POST)) + { + $this->company->create(); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('admin', 'browsecompany'), 'parent')); + } + + $this->lang->set('menugroup.company', 'admin'); + $this->lang->company->menu = $this->lang->admin->menu; + + $header['title'] = $this->lang->admin->common . $this->lang->colon . $this->lang->company->create; + $position[] = html::a($this->createLink('admin', 'browsecompany'), $this->lang->admin->company); + $position[] = $this->lang->company->create; + $this->view->header = $header; + $this->view->position = $position; + + $this->display(); + } + + /** + * Edit a company. + * + * @access public + * @return void + */ + public function edit() + { + if(!empty($_POST)) + { + $this->company->update(); + if(dao::isError()) die(js::error(dao::getError())); + die(js::alert($this->lang->company->successSaved)); + } + + $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->company->edit; + $position[] = $this->lang->company->edit; + $this->view->header = $header; + $this->view->position = $position; + $this->view->company = $this->company->getById($this->app->company->id); + + $this->display(); + } + + /** + * Delete a company. + * + * @param int $companyID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($companyID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->company->confirmDelete, $this->createLink('company', 'delete', "companyID=$companyID&confirm=yes")); + exit; + } + else + { + $this->company->delete($companyID); + echo js::locate($this->createLink('admin', 'browseCompany'), 'parent'); + exit; + } + } + + /** + * Company dynamic. + * + * @param string $browseType + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dynamic($browseType = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $this->app->loadLang('user'); + $this->app->loadLang('project'); + $this->loadModel('action'); + + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + /* Set the pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + + /* Set the user and type. */ + $account = $browseType == 'account' ? $param : 'all'; + $product = $browseType == 'product' ? $param : 'all'; + $project = $browseType == 'project' ? $param : 'all'; + $period = ($browseType == 'account' or $browseType == 'product' or $browseType == 'project') ? 'all' : $browseType; + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Get products' list.*/ + $products = $this->loadModel('product')->getPairs(); + $products = array($this->lang->product->select) + $products; + $this->view->products = $products; + + /* Get projects' list.*/ + $projects = $this->loadModel('project')->getPairs(); + $projects = array($this->lang->project->select) + $projects; + $this->view->projects = $projects; + + /* Get users.*/ + $users = $this->loadModel('user')->getPairs('nodeleted|noletter|noclosed'); + $users[''] = $this->lang->user->select; + $this->view->users = $users; + + /* The header and position. */ + $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic; + $this->view->position[] = $this->lang->company->dynamic; + + /* Get actions. */ + if($browseType != 'bysearch') + { + $actions = $this->action->getDynamic($account, $period, $orderBy, $pager, $product, $project); + } + else + { + $actions = $this->action->getDynamicBySearch($products, $projects, $queryID, $orderBy, $pager); + } + + /* Build search form. */ + $projects[0] = ''; + $products[0] = ''; + $users[''] = ''; + ksort($projects); + ksort($products); + $projects['all'] = $this->lang->project->allProject; + $products['all'] = $this->lang->product->allProduct; + $this->config->company->dynamic->search['actionURL'] = $this->createLink('company', 'dynamic', "browseType=bysearch¶m=myQueryID"); + $this->config->company->dynamic->search['queryID'] = $queryID; + $this->config->company->dynamic->search['params']['project']['values'] = $projects; + $this->config->company->dynamic->search['params']['product']['values'] = $products; + $this->config->company->dynamic->search['params']['actor']['values'] = $users; + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->company->dynamic->search); + + /* Assign. */ + $this->view->browseType = $browseType; + $this->view->account = $account; + $this->view->product = $product; + $this->view->project = $project; + $this->view->queryID = $queryID; + $this->view->actions = $actions; + $this->display(); + } +} diff --git a/module/company/lang/en.php b/module/company/lang/en.php index 8f06fc3b8f..667deabd55 100644 --- a/module/company/lang/en.php +++ b/module/company/lang/en.php @@ -1,39 +1,39 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->company->common = 'Company'; -$lang->company->index = "Index"; -$lang->company->create = "Create"; -$lang->company->edit = "Edit"; -$lang->company->read = "Info"; -$lang->company->update = "Update"; -$lang->company->delete = "Delete"; -$lang->company->browse = "User"; -$lang->company->dynamic = "Dynamic"; -$lang->company->depts = "Dept"; -$lang->company->orgView = 'Company'; - -$lang->company->confirmDelete = "Are you sure to delete this company?"; -$lang->company->successSaved = "Success saved"; - -$lang->company->id = 'ID'; -$lang->company->name = 'Name'; -$lang->company->phone = 'Phone'; -$lang->company->fax = 'Fax'; -$lang->company->address = 'Address'; -$lang->company->zipcode = 'Zipcode'; -$lang->company->website = 'Web site'; -$lang->company->backyard = 'Internal Site'; -$lang->company->pms = 'ZenTaoPMS Site'; -$lang->company->guest = 'Guest visit'; - -$lang->company->guestList[0] = 'Deny'; -$lang->company->guestList[1] = 'Allow'; + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->company->common = 'Company'; +$lang->company->index = "Index"; +$lang->company->create = "Create"; +$lang->company->edit = "Edit"; +$lang->company->read = "Info"; +$lang->company->update = "Update"; +$lang->company->delete = "Delete"; +$lang->company->browse = "User"; +$lang->company->dynamic = "Dynamic"; +$lang->company->depts = "Dept"; +$lang->company->orgView = 'Company'; + +$lang->company->confirmDelete = "Are you sure to delete this company?"; +$lang->company->successSaved = "Success saved"; + +$lang->company->id = 'ID'; +$lang->company->name = 'Name'; +$lang->company->phone = 'Phone'; +$lang->company->fax = 'Fax'; +$lang->company->address = 'Address'; +$lang->company->zipcode = 'Zipcode'; +$lang->company->website = 'Web site'; +$lang->company->backyard = 'Internal Site'; +$lang->company->pms = 'ZenTaoPMS Site'; +$lang->company->guest = 'Guest visit'; + +$lang->company->guestList[0] = 'Deny'; +$lang->company->guestList[1] = 'Allow'; diff --git a/module/company/lang/zh-cn.php b/module/company/lang/zh-cn.php index 19e2b7c517..a5f0571c48 100644 --- a/module/company/lang/zh-cn.php +++ b/module/company/lang/zh-cn.php @@ -1,39 +1,39 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->company->common = '组织视图'; -$lang->company->index = "组织视图首页"; -$lang->company->create = "新增公司"; -$lang->company->edit = "编辑公司"; -$lang->company->read = "公司信息"; -$lang->company->update = "更新公司"; -$lang->company->delete = "删除公司"; -$lang->company->browse = "用户列表"; -$lang->company->dynamic = "组织动态"; -$lang->company->depts = "部门列表"; -$lang->company->orgView = '组织视图'; - -$lang->company->confirmDelete = "您确定删除该公司吗?"; -$lang->company->successSaved = "成功保存"; - -$lang->company->id = '编号'; -$lang->company->name = '公司名称'; -$lang->company->phone = '联系电话'; -$lang->company->fax = '传真'; -$lang->company->address = '通讯地址'; -$lang->company->zipcode = '邮政编码'; -$lang->company->website = '公司网站'; -$lang->company->backyard = '公司内网'; -$lang->company->pms = 'PMS网站'; -$lang->company->guest = '匿名登录'; - -$lang->company->guestList[0] = '不允许'; -$lang->company->guestList[1] = '允许'; + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->company->common = '组织视图'; +$lang->company->index = "组织视图首页"; +$lang->company->create = "新增公司"; +$lang->company->edit = "编辑公司"; +$lang->company->read = "公司信息"; +$lang->company->update = "更新公司"; +$lang->company->delete = "删除公司"; +$lang->company->browse = "用户列表"; +$lang->company->dynamic = "组织动态"; +$lang->company->depts = "部门列表"; +$lang->company->orgView = '组织视图'; + +$lang->company->confirmDelete = "您确定删除该公司吗?"; +$lang->company->successSaved = "成功保存"; + +$lang->company->id = '编号'; +$lang->company->name = '公司名称'; +$lang->company->phone = '联系电话'; +$lang->company->fax = '传真'; +$lang->company->address = '通讯地址'; +$lang->company->zipcode = '邮政编码'; +$lang->company->website = '公司网站'; +$lang->company->backyard = '公司内网'; +$lang->company->pms = 'PMS网站'; +$lang->company->guest = '匿名登录'; + +$lang->company->guestList[0] = '不允许'; +$lang->company->guestList[1] = '允许'; diff --git a/module/company/lang/zh-tw.php b/module/company/lang/zh-tw.php index d2fb1f2202..4d0cef164d 100644 --- a/module/company/lang/zh-tw.php +++ b/module/company/lang/zh-tw.php @@ -1,39 +1,39 @@ - - * @package company - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->company->common = '組織視圖'; -$lang->company->index = "組織視圖首頁"; -$lang->company->create = "新增公司"; -$lang->company->edit = "編輯公司"; -$lang->company->read = "公司信息"; -$lang->company->update = "更新公司"; -$lang->company->delete = "刪除公司"; -$lang->company->browse = "用戶列表"; -$lang->company->dynamic = "組織動態"; -$lang->company->depts = "部門列表"; -$lang->company->orgView = '組織視圖'; - -$lang->company->confirmDelete = "您確定刪除該公司嗎?"; -$lang->company->successSaved = "成功保存"; - -$lang->company->id = '編號'; -$lang->company->name = '公司名稱'; -$lang->company->phone = '聯繫電話'; -$lang->company->fax = '傳真'; -$lang->company->address = '通訊地址'; -$lang->company->zipcode = '郵政編碼'; -$lang->company->website = '公司網站'; -$lang->company->backyard = '公司內網'; -$lang->company->pms = 'PMS網站'; -$lang->company->guest = '匿名登錄'; - -$lang->company->guestList[0] = '不允許'; -$lang->company->guestList[1] = '允許'; + + * @package company + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->company->common = '組織視圖'; +$lang->company->index = "組織視圖首頁"; +$lang->company->create = "新增公司"; +$lang->company->edit = "編輯公司"; +$lang->company->read = "公司信息"; +$lang->company->update = "更新公司"; +$lang->company->delete = "刪除公司"; +$lang->company->browse = "用戶列表"; +$lang->company->dynamic = "組織動態"; +$lang->company->depts = "部門列表"; +$lang->company->orgView = '組織視圖'; + +$lang->company->confirmDelete = "您確定刪除該公司嗎?"; +$lang->company->successSaved = "成功保存"; + +$lang->company->id = '編號'; +$lang->company->name = '公司名稱'; +$lang->company->phone = '聯繫電話'; +$lang->company->fax = '傳真'; +$lang->company->address = '通訊地址'; +$lang->company->zipcode = '郵政編碼'; +$lang->company->website = '公司網站'; +$lang->company->backyard = '公司內網'; +$lang->company->pms = 'PMS網站'; +$lang->company->guest = '匿名登錄'; + +$lang->company->guestList[0] = '不允許'; +$lang->company->guestList[1] = '允許'; diff --git a/module/company/model.php b/module/company/model.php index edb774aa87..c7a0df4d20 100644 --- a/module/company/model.php +++ b/module/company/model.php @@ -1,123 +1,123 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -?> -lang->company->menu, 'name', array($this->app->company->name)); - common::setMenuVars($this->lang->company->menu, 'addUser', array($dept)); - } - - /** - * Get company list. - * - * @access public - * @return void - */ - public function getList() - { - return $this->dao->select('*')->from(TABLE_COMPANY)->fetchAll(); - } - - /** - * Get the first company. - * - * @access public - * @return void - */ - public function getFirst() - { - return $this->dao->select('*')->from(TABLE_COMPANY)->orderBy('id')->limit(1)->fetch(); - } - - /** - * get company by domain. - * - * @param string $domain if empty, use current HTTP_HOST. - * @access public - * @return object - */ - public function getByDomain($domain = '') - { - if(empty($domain)) $domain = $this->server->http_host; - return $this->dao->findByPMS($domain)->from(TABLE_COMPANY)->fetch(); - } - - /** - * Get company info by id. - * - * @param int $companyID - * @access public - * @return object - */ - public function getByID($companyID = '') - { - return $this->dao->findById((int)$companyID)->from(TABLE_COMPANY)->fetch(); - } - - /** - * Create a company. - * - * @access public - * @return void - */ - public function create() - { - $company = fixer::input('post')->get(); - $this->dao->insert(TABLE_COMPANY) - ->data($company) - ->autoCheck() - ->batchCheck($this->config->company->create->requiredFields, 'notempty') - ->batchCheck('name,pms', 'unique') - ->exec(); - } - - /** - * Update a company. - * - * @access public - * @return void - */ - public function update() - { - $company = fixer::input('post')->stripTags('name')->get(); - $companyID = $this->app->company->id; - $this->dao->update(TABLE_COMPANY) - ->data($company) - ->autoCheck() - ->batchCheck($this->config->company->edit->requiredFields, 'notempty') - ->batchCheck('name,pms', 'unique', "id != '$companyID'") - ->where('id')->eq($companyID) - ->exec(); - } - - /** - * Delete a company. - * - * @param int $companyID - * @access public - * @return void - */ - public function delete($companyID) - { - return $this->dao->delete()->from(TABLE_COMPANY)->where('id')->eq((int)$companyID)->limit(1)->exec(); - } -} + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +?> +lang->company->menu, 'name', array($this->app->company->name)); + common::setMenuVars($this->lang->company->menu, 'addUser', array($dept)); + } + + /** + * Get company list. + * + * @access public + * @return void + */ + public function getList() + { + return $this->dao->select('*')->from(TABLE_COMPANY)->fetchAll(); + } + + /** + * Get the first company. + * + * @access public + * @return void + */ + public function getFirst() + { + return $this->dao->select('*')->from(TABLE_COMPANY)->orderBy('id')->limit(1)->fetch(); + } + + /** + * get company by domain. + * + * @param string $domain if empty, use current HTTP_HOST. + * @access public + * @return object + */ + public function getByDomain($domain = '') + { + if(empty($domain)) $domain = $this->server->http_host; + return $this->dao->findByPMS($domain)->from(TABLE_COMPANY)->fetch(); + } + + /** + * Get company info by id. + * + * @param int $companyID + * @access public + * @return object + */ + public function getByID($companyID = '') + { + return $this->dao->findById((int)$companyID)->from(TABLE_COMPANY)->fetch(); + } + + /** + * Create a company. + * + * @access public + * @return void + */ + public function create() + { + $company = fixer::input('post')->get(); + $this->dao->insert(TABLE_COMPANY) + ->data($company) + ->autoCheck() + ->batchCheck($this->config->company->create->requiredFields, 'notempty') + ->batchCheck('name,pms', 'unique') + ->exec(); + } + + /** + * Update a company. + * + * @access public + * @return void + */ + public function update() + { + $company = fixer::input('post')->stripTags('name')->get(); + $companyID = $this->app->company->id; + $this->dao->update(TABLE_COMPANY) + ->data($company) + ->autoCheck() + ->batchCheck($this->config->company->edit->requiredFields, 'notempty') + ->batchCheck('name,pms', 'unique', "id != '$companyID'") + ->where('id')->eq($companyID) + ->exec(); + } + + /** + * Delete a company. + * + * @param int $companyID + * @access public + * @return void + */ + public function delete($companyID) + { + return $this->dao->delete()->from(TABLE_COMPANY)->where('id')->eq((int)$companyID)->limit(1)->exec(); + } +} diff --git a/module/company/view/browse.html.php b/module/company/view/browse.html.php index 7598007955..746eee8f7e 100644 --- a/module/company/view/browse.html.php +++ b/module/company/view/browse.html.php @@ -1,78 +1,78 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
      -
      dept->common;?>
      -
      - -
      - user->create);echo '
      '; - common::printLink('company', 'browse', '', $lang->user->allUsers); echo '
      '; - common::printLink('dept', 'browse', '', $lang->dept->manage); - ?> -
      -
      -
      - - - - - - - user->nickname;?> - - - - - - - - - - - - - - - - nickname;?> - - - - - - - - - - -
      idAB;?>user->realname;?>user->account;?>user->email;?>user->gender;?>user->phone;?>user->join;?>user->last;?>user->visits;?>actions;?>
      id;?>account", $user->realname)) echo $user->realname;?>account;?>email);?>user->genderList->{$user->gender})) echo $lang->user->genderList->{$user->gender};?>phone;?>join;?>last);?>visits;?> - id&from=company", $lang->edit); - common::printLink('user', 'delete', "userID=$user->id", $lang->delete, "hiddenwin"); - ?> -
      -
      - - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
      +
      dept->common;?>
      +
      + +
      + user->create);echo '
      '; + common::printLink('company', 'browse', '', $lang->user->allUsers); echo '
      '; + common::printLink('dept', 'browse', '', $lang->dept->manage); + ?> +
      +
      +
      + + + + + + + user->nickname;?> + + + + + + + + + + + + + + + + nickname;?> + + + + + + + + + + +
      idAB;?>user->realname;?>user->account;?>user->email;?>user->gender;?>user->phone;?>user->join;?>user->last;?>user->visits;?>actions;?>
      id;?>account", $user->realname)) echo $user->realname;?>account;?>email);?>user->genderList->{$user->gender})) echo $lang->user->genderList->{$user->gender};?>phone;?>join;?>last);?>visits;?> + id&from=company", $lang->edit); + common::printLink('user', 'delete', "userID=$user->id", $lang->delete, "hiddenwin"); + ?> +
      +
      + + diff --git a/module/company/view/create.html.php b/module/company/view/create.html.php index 148be8dbac..88f3c2dc39 100644 --- a/module/company/view/create.html.php +++ b/module/company/view/create.html.php @@ -1,56 +1,56 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      company->create;?>
      company->name;?>
      company->phone;?>
      company->fax;?>
      company->address;?>
      company->zipcode;?>
      company->website;?>
      company->backyard;?>
      company->pms;?>
      company->guest;?>company->guestList);?>
      -
      - + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      company->create;?>
      company->name;?>
      company->phone;?>
      company->fax;?>
      company->address;?>
      company->zipcode;?>
      company->website;?>
      company->backyard;?>
      company->pms;?>
      company->guest;?>company->guestList);?>
      +
      + diff --git a/module/company/view/dynamic.html.php b/module/company/view/dynamic.html.php index 357b684648..fa23f21805 100644 --- a/module/company/view/dynamic.html.php +++ b/module/company/view/dynamic.html.php @@ -1,62 +1,62 @@ -dynamic view file of dashboard module of ZenTaoPMS. - * - * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) - * @license LGPL (http://www.gnu.org/licenses/lgpl.html) - * @author Chunsheng Wang - * @package dashboard - * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ - * @link http://www.zentao.net - */ -?> - - - -
      - ' . html::a(inlink('dynamic', "browseType=today"), $lang->action->dynamic->today) . ''; - echo '' . html::a(inlink('dynamic', "browseType=yesterday"), $lang->action->dynamic->yesterday) . ''; - echo '' . html::a(inlink('dynamic', "browseType=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; - echo '' . html::a(inlink('dynamic', "browseType=thisweek"), $lang->action->dynamic->thisWeek) . ''; - echo '' . html::a(inlink('dynamic', "browseType=lastweek"), $lang->action->dynamic->lastWeek) . ''; - echo '' . html::a(inlink('dynamic', "browseType=thismonth"), $lang->action->dynamic->thisMonth) . ''; - echo '' . html::a(inlink('dynamic', "browseType=lastmonth"), $lang->action->dynamic->lastMonth) . ''; - echo '' . html::a(inlink('dynamic', "browseType=all"), $lang->action->dynamic->all) . ''; - echo "" . html::select('account', $users, $account, 'onchange=changeUser(this.value)') . ''; - echo "" . html::select('product', $products, $product, 'onchange=changeProduct(this.value)') . ''; - echo "" . html::select('project', $projects, $project, 'onchange=changeProject(this.value)') . ''; - echo "" . html::a('#', $lang->action->dynamic->search) . ""; - ?> -
      -
      '>
      - - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - -
      action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
      date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
      show();?>
      - - +dynamic view file of dashboard module of ZenTaoPMS. + * + * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) + * @license LGPL (http://www.gnu.org/licenses/lgpl.html) + * @author Chunsheng Wang + * @package dashboard + * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ + * @link http://www.zentao.net + */ +?> + + + +
      + ' . html::a(inlink('dynamic', "browseType=today"), $lang->action->dynamic->today) . ''; + echo '' . html::a(inlink('dynamic', "browseType=yesterday"), $lang->action->dynamic->yesterday) . ''; + echo '' . html::a(inlink('dynamic', "browseType=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; + echo '' . html::a(inlink('dynamic', "browseType=thisweek"), $lang->action->dynamic->thisWeek) . ''; + echo '' . html::a(inlink('dynamic', "browseType=lastweek"), $lang->action->dynamic->lastWeek) . ''; + echo '' . html::a(inlink('dynamic', "browseType=thismonth"), $lang->action->dynamic->thisMonth) . ''; + echo '' . html::a(inlink('dynamic', "browseType=lastmonth"), $lang->action->dynamic->lastMonth) . ''; + echo '' . html::a(inlink('dynamic', "browseType=all"), $lang->action->dynamic->all) . ''; + echo "" . html::select('account', $users, $account, 'onchange=changeUser(this.value)') . ''; + echo "" . html::select('product', $products, $product, 'onchange=changeProduct(this.value)') . ''; + echo "" . html::select('project', $projects, $project, 'onchange=changeProject(this.value)') . ''; + echo "" . html::a('#', $lang->action->dynamic->search) . ""; + ?> +
      +
      '>
      + + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + +
      action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
      date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
      show();?>
      + + diff --git a/module/company/view/edit.html.php b/module/company/view/edit.html.php index 34ccc07bd6..f28aebe582 100644 --- a/module/company/view/edit.html.php +++ b/module/company/view/edit.html.php @@ -1,56 +1,56 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      company->edit;?>
      company->name;?>name, "class='text-1'");?>
      company->phone;?>phone, "class='text-1'");?>
      company->fax;?>fax, "class='text-1'");?>
      company->address;?>address, "class='text-1'");?>
      company->zipcode;?>zipcode, "class='text-1'");?>
      company->website;?>website, "class='text-1'");?>
      company->backyard;?>backyard, "class='text-1'");?>
      company->pms;?>pms, "class='text-1'");?>
      company->guest;?>company->guestList, $company->guest);?>
      -
      - + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      company->edit;?>
      company->name;?>name, "class='text-1'");?>
      company->phone;?>phone, "class='text-1'");?>
      company->fax;?>fax, "class='text-1'");?>
      company->address;?>address, "class='text-1'");?>
      company->zipcode;?>zipcode, "class='text-1'");?>
      company->website;?>website, "class='text-1'");?>
      company->backyard;?>backyard, "class='text-1'");?>
      company->pms;?>pms, "class='text-1'");?>
      company->guest;?>company->guestList, $company->guest);?>
      +
      + diff --git a/module/convert/control.php b/module/convert/control.php index af46236284..f2194a82f3 100644 --- a/module/convert/control.php +++ b/module/convert/control.php @@ -1,240 +1,240 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -class convert extends control -{ - /** - * Index page of convert. - * - * @access public - * @return void - */ - public function index() - { - $this->convert->saveState(); - $this->view->header->title = $this->lang->convert->common; - $this->display(); - } - - /** - * Select the source system. - * - * @access public - * @return void - */ - public function selectSource() - { - $this->view->header->title = $this->lang->convert->common . $this->lang->colon; - $this->display(); - } - - /** - * Set configs of converter. - * - * This is the extrance of every system. It will call the set function of corresponding module. - * - * @access public - * @return void - */ - public function setConfig() - { - if(!$this->post->source) - { - echo js::alert($this->lang->convert->mustSelectSource); - die(js::locate('back')); - } - list($sourceName, $version) = explode('_', $this->post->source); - $setFunc = "set$sourceName"; - $this->view->header->title = $this->lang->convert->setting; - $this->view->source = $sourceName; - $this->view->version = $version; - $this->view->setting = $this->fetch('convert', $setFunc, "version=$version"); - $this->display(); - } - - /** - * The setting page of bugfree. - * - * @param string $version - * @access public - * @return void - */ - public function setBugFree($version) - { - $this->view->source = 'BugFree'; - $this->view->version = $version; - $this->view->tablePrefix = $version > 1 ? 'bf_' : ''; - $this->view->dbName = $version > 1 ? 'bugfree2' : 'BugFree'; - $this->view->dbCharset = 'utf8'; - $this->display(); - } - - /** - * The setting page of Redmine. - * - * @param string $version - * @access public - * @return void - */ - public function setRedmine($version) - { - $this->view->source = 'Redmine'; - $this->view->version = $version; - $this->view->dbName = 'redmine'; - $this->view->dbCharset = 'utf8'; - $this->display(); - } - - /** - * Check config. Same as setConfig. - * - * @access public - * @return void - */ - public function checkConfig() - { - $checkFunc = 'check' . $this->post->source; - $this->view->header->title = $this->lang->convert->checkConfig; - $this->view->source = $this->post->source; - $this->view->checkResult = $this->fetch('convert', $checkFunc, "version={$this->post->version}"); - $this->display(); - } - - /** - * Check settings of bugfree. - * - * @param int $version - * @access public - * @return void - */ - public function checkBugFree($version) - { - helper::import('./converter/bugfree.php'); - $converter = new bugfreeConvertModel(); - - /* Check it. */ - $checkInfo['db'] = $converter->connectDB(); - //if(is_object($checkInfo['db'])) $checkInfo['table'] = $converter->checkTables(); - $checkInfo['path'] = $converter->checkPath(); - - /* Compute the checking result. */ - $result = 'pass'; - if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail'; - - /* Assign. */ - $this->view->version = $version; - $this->view->source = 'bugfree'; - $this->view->result = $result; - $this->view->checkInfo = $checkInfo; - $this->display(); - } - - /** - * Check settings of Redmine. - * - * @param int $version - * @access public - * @return void - */ - public function checkRedmine($version) - { - helper::import('./converter/redmine.php'); - $converter = new redmineConvertModel(); - - /* Check it. */ - $checkInfo['db'] = $converter->connectDB(); - $checkInfo['path'] = $converter->checkPath(); - - $this->view->trackers = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('trackers')->fetchAll('id', $autoCompany = false); - $this->view->statuses = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('issue_statuses')->fetchAll('id', $autoCompany = false); - $this->view->pries = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('enumerations')->where('type')->eq('IssuePriority')->fetchAll('id', $autoCompany = false); - /* Compute the checking result. */ - $result = 'pass'; - if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail'; - - $this->app->loadLang('bug'); - $this->app->loadLang('story'); - $this->app->loadLang('task'); - $this->view->aimTypeList['bug'] = 'bug'; - $this->view->aimTypeList['task'] = 'task'; - $this->view->aimTypeList['story'] = 'story'; - - /* Assign. */ - $this->view->version = $version; - $this->view->source = 'Redmine'; - $this->view->result = $result; - $this->view->checkInfo = $checkInfo; - $this->display(); - } - - /** - * Execute the converting. - * - * @access public - * @return void - */ - public function execute() - { - $convertFunc = 'convert' . $this->post->source; - $this->view->header->title = $this->lang->convert->execute; - $this->view->source = $this->post->source; - $this->view->version = $this->post->version; - - $this->view->executeResult = $this->fetch('convert', $convertFunc, "version={$this->post->version}"); - $this->display(); - } - - /** - * Convert bugfree. - * - * @param int $version - * @access public - * @return void - */ - public function convertBugFree($version) - { - helper::import('./converter/bugfree.php'); - helper::import("./converter/bugfree$version.php"); - $className = "bugfree{$version}ConvertModel"; - $converter = new $className(); - $this->view->version = $version; - $this->view->result = $converter->execute($version); - $this->view->info = bugfreeConvertModel::$info; - $this->display(); - } - - /** - * convert redmine - * - * @param int $version - * @access public - * @return void - */ - public function convertRedmine($version) - { - helper::import('./converter/redmine.php'); - helper::import("./converter/redmine$version.php"); - $className = "redmine11ConvertModel"; - $redmine->aimTypes = $this->post->aimTypes; - $redmine->statusTypes['bug'] = $this->post->statusTypesOfBug; - $redmine->statusTypes['story'] = $this->post->statusTypesOfStory; - $redmine->statusTypes['task'] = $this->post->statusTypesOfTask; - $redmine->priTypes['bug'] = $this->post->priTypesOfBug; - $redmine->priTypes['story'] = $this->post->priTypesOfStory; - $redmine->priTypes['task'] = $this->post->priTypesOfTask; - - $converter = new $className($redmine); - $this->view->version = $version; - $this->view->result = $converter->execute($version); - $this->view->info = redmineConvertModel::$info; - $this->display(); - } -} + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +class convert extends control +{ + /** + * Index page of convert. + * + * @access public + * @return void + */ + public function index() + { + $this->convert->saveState(); + $this->view->header->title = $this->lang->convert->common; + $this->display(); + } + + /** + * Select the source system. + * + * @access public + * @return void + */ + public function selectSource() + { + $this->view->header->title = $this->lang->convert->common . $this->lang->colon; + $this->display(); + } + + /** + * Set configs of converter. + * + * This is the extrance of every system. It will call the set function of corresponding module. + * + * @access public + * @return void + */ + public function setConfig() + { + if(!$this->post->source) + { + echo js::alert($this->lang->convert->mustSelectSource); + die(js::locate('back')); + } + list($sourceName, $version) = explode('_', $this->post->source); + $setFunc = "set$sourceName"; + $this->view->header->title = $this->lang->convert->setting; + $this->view->source = $sourceName; + $this->view->version = $version; + $this->view->setting = $this->fetch('convert', $setFunc, "version=$version"); + $this->display(); + } + + /** + * The setting page of bugfree. + * + * @param string $version + * @access public + * @return void + */ + public function setBugFree($version) + { + $this->view->source = 'BugFree'; + $this->view->version = $version; + $this->view->tablePrefix = $version > 1 ? 'bf_' : ''; + $this->view->dbName = $version > 1 ? 'bugfree2' : 'BugFree'; + $this->view->dbCharset = 'utf8'; + $this->display(); + } + + /** + * The setting page of Redmine. + * + * @param string $version + * @access public + * @return void + */ + public function setRedmine($version) + { + $this->view->source = 'Redmine'; + $this->view->version = $version; + $this->view->dbName = 'redmine'; + $this->view->dbCharset = 'utf8'; + $this->display(); + } + + /** + * Check config. Same as setConfig. + * + * @access public + * @return void + */ + public function checkConfig() + { + $checkFunc = 'check' . $this->post->source; + $this->view->header->title = $this->lang->convert->checkConfig; + $this->view->source = $this->post->source; + $this->view->checkResult = $this->fetch('convert', $checkFunc, "version={$this->post->version}"); + $this->display(); + } + + /** + * Check settings of bugfree. + * + * @param int $version + * @access public + * @return void + */ + public function checkBugFree($version) + { + helper::import('./converter/bugfree.php'); + $converter = new bugfreeConvertModel(); + + /* Check it. */ + $checkInfo['db'] = $converter->connectDB(); + //if(is_object($checkInfo['db'])) $checkInfo['table'] = $converter->checkTables(); + $checkInfo['path'] = $converter->checkPath(); + + /* Compute the checking result. */ + $result = 'pass'; + if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail'; + + /* Assign. */ + $this->view->version = $version; + $this->view->source = 'bugfree'; + $this->view->result = $result; + $this->view->checkInfo = $checkInfo; + $this->display(); + } + + /** + * Check settings of Redmine. + * + * @param int $version + * @access public + * @return void + */ + public function checkRedmine($version) + { + helper::import('./converter/redmine.php'); + $converter = new redmineConvertModel(); + + /* Check it. */ + $checkInfo['db'] = $converter->connectDB(); + $checkInfo['path'] = $converter->checkPath(); + + $this->view->trackers = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('trackers')->fetchAll('id', $autoCompany = false); + $this->view->statuses = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('issue_statuses')->fetchAll('id', $autoCompany = false); + $this->view->pries = $this->dao->dbh($converter->sourceDBH)->select('id, name')->from('enumerations')->where('type')->eq('IssuePriority')->fetchAll('id', $autoCompany = false); + /* Compute the checking result. */ + $result = 'pass'; + if(!is_object($checkInfo['db']) or !$checkInfo['path']) $result = 'fail'; + + $this->app->loadLang('bug'); + $this->app->loadLang('story'); + $this->app->loadLang('task'); + $this->view->aimTypeList['bug'] = 'bug'; + $this->view->aimTypeList['task'] = 'task'; + $this->view->aimTypeList['story'] = 'story'; + + /* Assign. */ + $this->view->version = $version; + $this->view->source = 'Redmine'; + $this->view->result = $result; + $this->view->checkInfo = $checkInfo; + $this->display(); + } + + /** + * Execute the converting. + * + * @access public + * @return void + */ + public function execute() + { + $convertFunc = 'convert' . $this->post->source; + $this->view->header->title = $this->lang->convert->execute; + $this->view->source = $this->post->source; + $this->view->version = $this->post->version; + + $this->view->executeResult = $this->fetch('convert', $convertFunc, "version={$this->post->version}"); + $this->display(); + } + + /** + * Convert bugfree. + * + * @param int $version + * @access public + * @return void + */ + public function convertBugFree($version) + { + helper::import('./converter/bugfree.php'); + helper::import("./converter/bugfree$version.php"); + $className = "bugfree{$version}ConvertModel"; + $converter = new $className(); + $this->view->version = $version; + $this->view->result = $converter->execute($version); + $this->view->info = bugfreeConvertModel::$info; + $this->display(); + } + + /** + * convert redmine + * + * @param int $version + * @access public + * @return void + */ + public function convertRedmine($version) + { + helper::import('./converter/redmine.php'); + helper::import("./converter/redmine$version.php"); + $className = "redmine11ConvertModel"; + $redmine->aimTypes = $this->post->aimTypes; + $redmine->statusTypes['bug'] = $this->post->statusTypesOfBug; + $redmine->statusTypes['story'] = $this->post->statusTypesOfStory; + $redmine->statusTypes['task'] = $this->post->statusTypesOfTask; + $redmine->priTypes['bug'] = $this->post->priTypesOfBug; + $redmine->priTypes['story'] = $this->post->priTypesOfStory; + $redmine->priTypes['task'] = $this->post->priTypesOfTask; + + $converter = new $className($redmine); + $this->view->version = $version; + $this->view->result = $converter->execute($version); + $this->view->info = redmineConvertModel::$info; + $this->display(); + } +} diff --git a/module/convert/converter/bugfree.php b/module/convert/converter/bugfree.php index 8d520dbc3c..e829fc4e80 100644 --- a/module/convert/converter/bugfree.php +++ b/module/convert/converter/bugfree.php @@ -1,88 +1,88 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -class bugfreeConvertModel extends convertModel -{ - public $map = array(); - public $filePath = ''; - static public $info = array(); - - /** - * Connect to db auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - parent::connectDB(); - } - - /** - * Check table. - * - * @access public - * @return bool - */ - public function checkTables() - { - return true; - } - - /** - * Check the install path. - * - * @access public - * @return bool - */ - public function checkPath() - { - $this->setPath(); - return file_exists($this->filePath); - } - - /** - * Set the path of attachments. - * - * @access public - * @return bool - */ - public function setPath() - { - $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'BugFile' . $this->app->getPathFix(); - } - - /** - * Excute the convert. - * - * @param int $version - * @access public - * @return void - */ - public function execute($version) - { - } - - /** - * Clear rows added in converting. - * - * @access public - * @return void - */ - public function clear() - { - foreach($this->session->state as $table => $maxID) - { - $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); - } - } -} + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +class bugfreeConvertModel extends convertModel +{ + public $map = array(); + public $filePath = ''; + static public $info = array(); + + /** + * Connect to db auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + parent::connectDB(); + } + + /** + * Check table. + * + * @access public + * @return bool + */ + public function checkTables() + { + return true; + } + + /** + * Check the install path. + * + * @access public + * @return bool + */ + public function checkPath() + { + $this->setPath(); + return file_exists($this->filePath); + } + + /** + * Set the path of attachments. + * + * @access public + * @return bool + */ + public function setPath() + { + $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'BugFile' . $this->app->getPathFix(); + } + + /** + * Excute the convert. + * + * @param int $version + * @access public + * @return void + */ + public function execute($version) + { + } + + /** + * Clear rows added in converting. + * + * @access public + * @return void + */ + public function clear() + { + foreach($this->session->state as $table => $maxID) + { + $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); + } + } +} diff --git a/module/convert/converter/bugfree1.php b/module/convert/converter/bugfree1.php index 33e47d16b1..2e60b09fab 100644 --- a/module/convert/converter/bugfree1.php +++ b/module/convert/converter/bugfree1.php @@ -1,318 +1,318 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -class bugfree1ConvertModel extends bugfreeConvertModel -{ - /** - * Execute the convert. - * - * @access public - * @return array - */ - public function execute() - { - $this->clear(); - $this->convertGroup(); - $result['users'] = $this->convertUser(); - $result['projects'] = $this->convertProject(); - $result['modules'] = $this->convertModule(); - $result['bugs'] = $this->convertBug(); - $result['actions'] = $this->convertAction(); - $result['files'] = $this->convertFile(); - $this->dao->dbh($this->dbh); - $this->loadModel('tree')->fixModulePath(); - return $result; - } - - /** - * Convert groups. - * - * @access public - * @return void - */ - public function convertGroup() - { - $groups = $this->dao->dbh($this->sourceDBH) - ->select("groupID AS id, groupName AS name, groupUser AS users") - ->from('BugGroup') - ->fetchAll('id', $autoCompany = false); - foreach($groups as $groupID => $group) - { - /* Explode into array. */ - $groupUsers = explode(',', $group->users); - unset($group->id); - unset($group->users); - - /* Insert the group. */ - $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec(); - $zentaoGroupID = $this->dao->lastInsertId(); - - /* Insert account. */ - foreach($groupUsers as $account) - { - if(empty($account)) continue; - $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->set('`group`')->eq($zentaoGroupID)->set('account')->eq($account)->exec(); - } - } - } - - /** - * Convert user. - * - * @access public - * @return int converted user count - */ - public function convertUser() - { - /* Get users exist in the system. */ - $activeUsers = $this->dao - ->dbh($this->sourceDBH) - ->select("username AS account, userpassword AS password, realname, email") - ->from('BugUser') - ->orderBy('userID ASC') - ->fetchAll('account', $autoCompany = false); - - /* Get users in histories. */ - $allUsers = $this->dao->select("distinct(username) AS account")->from('BugHistory')->fetchPairs('', '', $autoCompany = false); - - /* Merge them. */ - foreach($allUsers as $key => $account) - { - if(isset($activeUsers[$account])) - { - $allUsers[$key] = $activeUsers[$account]; - } - else - { - $allUsers[$key] = array('account' => $account, 'realname' => $account, 'deleted' => '1'); - } - } - foreach($activeUsers as $account => $user) if(!isset($allUsers[$account])) $allUsers[$account] = $user; - - /* Insert into zentao. */ - $convertCount = 0; - foreach($allUsers as $account => $user) - { - if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account')) - { - $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); - $convertCount ++; - } - else - { - self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account); - } - } - return $convertCount; - } - - /** - * Convert project in bugfree to product in zentao. - * - * @access public - * @return int converted project count - */ - public function convertProject() - { - $projects = $this->dao->dbh($this->sourceDBH)->select("projectID AS id, projectName AS name")->from('BugProject')->fetchAll('id', $autoCompany = false); - foreach($projects as $projectID => $project) - { - unset($project->id); - $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec(); - $this->map['product'][$projectID] = $this->dao->lastInsertID(); - } - return count($projects); - } - - /** - * Convert modules. - * - * @access public - * @return int converted modules count - */ - public function convertModule() - { - $this->map['module'][0] = 0; - $modules = $this->dao - ->dbh($this->sourceDBH) - ->select( - 'moduleID AS id, - projectID AS root, - moduleName AS name, - moduleGrade AS grade, - parentID AS parent, - "bug" AS type') - ->from('BugModule') - ->orderBy('id ASC') - ->fetchAll('id', $autoCompany = false); - foreach($modules as $moduleID => $module) - { - $module->root = $this->map['product'][$module->root]; - unset($module->id); - $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec(); - $this->map['module'][$moduleID] = $this->dao->lastInsertID(); - } - - /* Update parents. */ - foreach($modules as $oldModuleID => $module) - { - $newModuleID = $this->map['module'][$oldModuleID]; - $newParentID = $this->map['module'][$module->parent]; - $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec(); - } - return count($modules); - } - - /** - * Convert bugs. - * - * @access public - * @return int converted bugs count. - */ - public function convertBug() - { - $bugs = $this->dao - ->dbh($this->sourceDBH) - ->select(' - bugID AS id, - projectID AS product, - moduleID AS module, - bugTitle AS title, - bugSeverity AS severity, - bugType AS type, - bugOS AS os, - bugStatus AS status, - mailto, - openedBy, openedDate, openedBuild, - assignedTo, assignedDate, - resolvedBy, resolution, resolvedBuild, resolvedDate, - closedBy, closedDate, - lastEditedBy, lastEditedDate, - linkID as duplicateBug - ') - ->from('BugInfo') - ->orderBy('bugID') - ->fetchAll('id', $autoCompany = false); - foreach($bugs as $bugID => $bug) - { - /* Adjust some fields of bug. */ - $bugID = (int)$bugID; - unset($bug->id); - if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed'; - $bug->type = strtolower($bug->type); - $bug->os = strtolower($bug->os); - $bug->browser = 'all'; - $bug->resolution = str_replace(' ','', strtolower($bug->resolution)); - $bug->product = $this->map['product'][$bug->product]; - $bug->module = $this->map['module'][$bug->module]; - $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); - $this->map['bug'][$bugID] = $this->dao->lastInsertID(); - } - - /* Update duplicated bugs. */ - foreach($this->map['bug'] as $oldBugID => $newBugID) - { - $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec(); - } - return count($bugs); - } - - /** - * Convert actions. - * - * @access public - * @return int converted actions count. - */ - public function convertAction() - { - $actions = $this->dao - ->dbh($this->sourceDBH) - ->select(" - 'bug' AS objectType, - bugID AS objectID, - userName AS actor, - action, - fullInfo AS comment, - actionDate AS date") - ->from('BugHistory') - ->orderBy('bugID, historyID') - ->fetchGroup('objectID', '', $autoCompany = false); - $convertCount = 0; - foreach($actions as $bugID => $bugActions) - { - /* Get the related bugID. */ - $bugID = (int)$bugID; - $zentaoBugID = $this->map['bug'][$bugID]; - - /* Process actions. */ - foreach($bugActions as $key => $action) - { - $action->objectID = $zentaoBugID; - if($key == 0) - { - $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('steps')->eq(nl2br($action->comment))->where('id')->eq($zentaoBugID)->exec(); - $action->comment = ''; - } - $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec(); - $convertCount ++; - } - } - return $convertCount; - } - - /** - * Convert files. - * - * @access public - * @return int converted files count. - */ - public function convertFile() - { - $this->setPath(); - $files = $this->dao->dbh($this->sourceDBH) - ->select(" - fileName AS pathname, - fileTitle AS title, - fileType AS extension, - fileSize AS size, - 'bug' AS objectType, - bugID AS objectID, - addUser AS addedBy, - addDate AS addedDate - ") - ->from('BugFile') - ->orderBy('fileID') - ->fetchAll('', $autoCompany = false); - foreach($files as $file) - { - $file->objectID = $this->map['bug'][(int)$file->objectID]; - if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024); - if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024); - $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); - - /* Copy files. */ - $soureFile = $this->filePath . $file->pathname; - if(!file_exists($soureFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); - continue; - } - $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; - $targetPath = dirname($targetFile); - if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); - if(!copy($soureFile, $targetFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); - } - } - return count($files); - } -} + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +class bugfree1ConvertModel extends bugfreeConvertModel +{ + /** + * Execute the convert. + * + * @access public + * @return array + */ + public function execute() + { + $this->clear(); + $this->convertGroup(); + $result['users'] = $this->convertUser(); + $result['projects'] = $this->convertProject(); + $result['modules'] = $this->convertModule(); + $result['bugs'] = $this->convertBug(); + $result['actions'] = $this->convertAction(); + $result['files'] = $this->convertFile(); + $this->dao->dbh($this->dbh); + $this->loadModel('tree')->fixModulePath(); + return $result; + } + + /** + * Convert groups. + * + * @access public + * @return void + */ + public function convertGroup() + { + $groups = $this->dao->dbh($this->sourceDBH) + ->select("groupID AS id, groupName AS name, groupUser AS users") + ->from('BugGroup') + ->fetchAll('id', $autoCompany = false); + foreach($groups as $groupID => $group) + { + /* Explode into array. */ + $groupUsers = explode(',', $group->users); + unset($group->id); + unset($group->users); + + /* Insert the group. */ + $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec(); + $zentaoGroupID = $this->dao->lastInsertId(); + + /* Insert account. */ + foreach($groupUsers as $account) + { + if(empty($account)) continue; + $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->set('`group`')->eq($zentaoGroupID)->set('account')->eq($account)->exec(); + } + } + } + + /** + * Convert user. + * + * @access public + * @return int converted user count + */ + public function convertUser() + { + /* Get users exist in the system. */ + $activeUsers = $this->dao + ->dbh($this->sourceDBH) + ->select("username AS account, userpassword AS password, realname, email") + ->from('BugUser') + ->orderBy('userID ASC') + ->fetchAll('account', $autoCompany = false); + + /* Get users in histories. */ + $allUsers = $this->dao->select("distinct(username) AS account")->from('BugHistory')->fetchPairs('', '', $autoCompany = false); + + /* Merge them. */ + foreach($allUsers as $key => $account) + { + if(isset($activeUsers[$account])) + { + $allUsers[$key] = $activeUsers[$account]; + } + else + { + $allUsers[$key] = array('account' => $account, 'realname' => $account, 'deleted' => '1'); + } + } + foreach($activeUsers as $account => $user) if(!isset($allUsers[$account])) $allUsers[$account] = $user; + + /* Insert into zentao. */ + $convertCount = 0; + foreach($allUsers as $account => $user) + { + if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account')) + { + $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); + $convertCount ++; + } + else + { + self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account); + } + } + return $convertCount; + } + + /** + * Convert project in bugfree to product in zentao. + * + * @access public + * @return int converted project count + */ + public function convertProject() + { + $projects = $this->dao->dbh($this->sourceDBH)->select("projectID AS id, projectName AS name")->from('BugProject')->fetchAll('id', $autoCompany = false); + foreach($projects as $projectID => $project) + { + unset($project->id); + $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec(); + $this->map['product'][$projectID] = $this->dao->lastInsertID(); + } + return count($projects); + } + + /** + * Convert modules. + * + * @access public + * @return int converted modules count + */ + public function convertModule() + { + $this->map['module'][0] = 0; + $modules = $this->dao + ->dbh($this->sourceDBH) + ->select( + 'moduleID AS id, + projectID AS root, + moduleName AS name, + moduleGrade AS grade, + parentID AS parent, + "bug" AS type') + ->from('BugModule') + ->orderBy('id ASC') + ->fetchAll('id', $autoCompany = false); + foreach($modules as $moduleID => $module) + { + $module->root = $this->map['product'][$module->root]; + unset($module->id); + $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec(); + $this->map['module'][$moduleID] = $this->dao->lastInsertID(); + } + + /* Update parents. */ + foreach($modules as $oldModuleID => $module) + { + $newModuleID = $this->map['module'][$oldModuleID]; + $newParentID = $this->map['module'][$module->parent]; + $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec(); + } + return count($modules); + } + + /** + * Convert bugs. + * + * @access public + * @return int converted bugs count. + */ + public function convertBug() + { + $bugs = $this->dao + ->dbh($this->sourceDBH) + ->select(' + bugID AS id, + projectID AS product, + moduleID AS module, + bugTitle AS title, + bugSeverity AS severity, + bugType AS type, + bugOS AS os, + bugStatus AS status, + mailto, + openedBy, openedDate, openedBuild, + assignedTo, assignedDate, + resolvedBy, resolution, resolvedBuild, resolvedDate, + closedBy, closedDate, + lastEditedBy, lastEditedDate, + linkID as duplicateBug + ') + ->from('BugInfo') + ->orderBy('bugID') + ->fetchAll('id', $autoCompany = false); + foreach($bugs as $bugID => $bug) + { + /* Adjust some fields of bug. */ + $bugID = (int)$bugID; + unset($bug->id); + if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed'; + $bug->type = strtolower($bug->type); + $bug->os = strtolower($bug->os); + $bug->browser = 'all'; + $bug->resolution = str_replace(' ','', strtolower($bug->resolution)); + $bug->product = $this->map['product'][$bug->product]; + $bug->module = $this->map['module'][$bug->module]; + $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); + $this->map['bug'][$bugID] = $this->dao->lastInsertID(); + } + + /* Update duplicated bugs. */ + foreach($this->map['bug'] as $oldBugID => $newBugID) + { + $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec(); + } + return count($bugs); + } + + /** + * Convert actions. + * + * @access public + * @return int converted actions count. + */ + public function convertAction() + { + $actions = $this->dao + ->dbh($this->sourceDBH) + ->select(" + 'bug' AS objectType, + bugID AS objectID, + userName AS actor, + action, + fullInfo AS comment, + actionDate AS date") + ->from('BugHistory') + ->orderBy('bugID, historyID') + ->fetchGroup('objectID', '', $autoCompany = false); + $convertCount = 0; + foreach($actions as $bugID => $bugActions) + { + /* Get the related bugID. */ + $bugID = (int)$bugID; + $zentaoBugID = $this->map['bug'][$bugID]; + + /* Process actions. */ + foreach($bugActions as $key => $action) + { + $action->objectID = $zentaoBugID; + if($key == 0) + { + $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('steps')->eq(nl2br($action->comment))->where('id')->eq($zentaoBugID)->exec(); + $action->comment = ''; + } + $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec(); + $convertCount ++; + } + } + return $convertCount; + } + + /** + * Convert files. + * + * @access public + * @return int converted files count. + */ + public function convertFile() + { + $this->setPath(); + $files = $this->dao->dbh($this->sourceDBH) + ->select(" + fileName AS pathname, + fileTitle AS title, + fileType AS extension, + fileSize AS size, + 'bug' AS objectType, + bugID AS objectID, + addUser AS addedBy, + addDate AS addedDate + ") + ->from('BugFile') + ->orderBy('fileID') + ->fetchAll('', $autoCompany = false); + foreach($files as $file) + { + $file->objectID = $this->map['bug'][(int)$file->objectID]; + if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024); + if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024); + $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); + + /* Copy files. */ + $soureFile = $this->filePath . $file->pathname; + if(!file_exists($soureFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); + continue; + } + $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; + $targetPath = dirname($targetFile); + if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); + if(!copy($soureFile, $targetFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); + } + } + return count($files); + } +} diff --git a/module/convert/converter/bugfree2.php b/module/convert/converter/bugfree2.php index f436b7a7bc..acac3ab1c1 100644 --- a/module/convert/converter/bugfree2.php +++ b/module/convert/converter/bugfree2.php @@ -1,530 +1,530 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -class bugfree2ConvertModel extends bugfreeConvertModel -{ - /** - * Execute the converter. - * - * @access public - * @return array - */ - public function execute() - { - $this->clear(); - $this->setTable(); - $this->convertGroup(); - $result['users'] = $this->convertUser(); - $result['projects'] = $this->convertProject(); - $result['modules'] = $this->convertModule(); - $result['bugs'] = $this->convertBug(); - $result['cases'] = $this->convertCase(); - $result['results'] = $this->convertResult(); - $result['actions'] = $this->convertAction(); - $result['files'] = $this->convertFile(); - $this->dao->dbh($this->dbh); - $this->loadModel('tree')->fixModulePath(); - return $result; - } - - /** - * Set table names. - * - * @access public - * @return void - */ - public function setTable() - { - $dbPrefix = $this->post->dbPrefix; - define('BUGFREE_TABLE_OPTION', $dbPrefix . 'TestOptions'); - define('BUGFREE_TABLE_USER', $dbPrefix . 'TestUser'); - define('BUGFREE_TABLE_PROJECT', $dbPrefix . 'TestProject'); - define('BUGFREE_TABLE_MODULE', $dbPrefix . 'TestModule'); - define('BUGFREE_TABLE_BUGINFO', $dbPrefix . 'BugInfo'); - define('BUGFREE_TABLE_CASEINFO', $dbPrefix . 'CaseInfo'); - define('BUGFREE_TABLE_RESULTINFO', $dbPrefix . 'ResultInfo'); - define('BUGFREE_TABLE_ACTION', $dbPrefix . 'TestAction'); - define('BUGFREE_TABLE_FILE', $dbPrefix . 'TestFile'); - define('BUGFREE_TABLE_HISTORY', $dbPrefix . 'TestHistory'); - define('BUGFREE_TABLE_GROUP', $dbPrefix . 'TestGroup'); - } - - /** - * Get the version of bugfree2.x. - * - * @access public - * @return int - */ - public function getBugFreeVersion() - { - return $this->dao->dbh($this->sourceDBH) - ->select("optionValue as version")->from(BUGFREE_TABLE_OPTION) - ->where('OptionName')->eq('dbVersion') - ->fetch('version', $autoCompany = false); - - } - - /** - * Convert user. - * - * @access public - * @return int converted user count - */ - public function convertUser() - { - /* Get all user list. */ - $users = $this->dao - ->dbh($this->sourceDBH) - ->select("username AS account, userpassword AS password, realname, email, isDroped AS deleted") - ->from(BUGFREE_TABLE_USER) - ->orderBy('userID ASC') - ->fetchAll('account', $autoCompany = false); - - /* Insert into zentao. */ - $convertCount = 0; - foreach($users as $account => $user) - { - if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account')) - { - $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); - $convertCount ++; - } - else - { - self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account); - } - } - return $convertCount; - } - - /** - * Convert groups. - * - * @access public - * @return void converted group count. - */ - public function convertGroup() - { - if(!$this->tableExists(BUGFREE_TABLE_GROUP)) return false; - $groups = $this->dao->dbh($this->sourceDBH) - ->select("groupID AS id, groupName AS name, groupUser AS users") - ->from(BUGFREE_TABLE_GROUP) - ->fetchAll('id', $autoCompany = false); - foreach($groups as $groupID => $group) - { - /* Fix the group data. */ - if($group->name == '[All Users]') continue; - $groupUsers = explode(',', $group->users); - unset($group->id); - unset($group->users); - - /* Insert into zentao's group table. */ - $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec(); - $zentaoGroupID = $this->dao->lastInsertId(); - - /* Insert into zentao's usergroup table. */ - foreach($groupUsers as $account) - { - if(empty($account)) continue; - $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP) - ->set('`group`')->eq($zentaoGroupID) - ->set('account')->eq($account) - ->exec(); - } - } - } - - /** - * Convert projects. - * - * @access public - * @return int converted projects count. - */ - public function convertProject() - { - $projects = $this->dao->dbh($this->sourceDBH) - ->select("projectID AS id, projectName AS name, isDroped AS deleted") - ->from(BUGFREE_TABLE_PROJECT) - ->fetchAll('id', $autoComapny = false); - foreach($projects as $projectID => $project) - { - unset($project->id); - $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec(); - $this->map['product'][$projectID] = $this->dao->lastInsertID(); - } - return count($projects); - } - - /** - * Convert modules. - * - * @access public - * @return int converted modules count. - */ - public function convertModule() - { - $this->map['module'][0] = 0; - $modules = $this->dao - ->dbh($this->sourceDBH) - ->select( - 'moduleID AS id, - moduleType as type, - projectID AS root, - moduleName AS name, - moduleGrade AS grade, - parentID AS parent, - displayOrder AS `order`') - ->from(BUGFREE_TABLE_MODULE) - ->orderBy('id ASC') - ->fetchAll('id', $autoCompany = false); - foreach($modules as $moduleID => $module) - { - $module->root = $this->map['product'][$module->root]; - $module->type = strtolower($module->type); - unset($module->id); - $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec(); - $this->map['module'][$moduleID] = $this->dao->lastInsertID(); - } - - /* Update parent. */ - foreach($modules as $oldModuleID => $module) - { - $newModuleID = $this->map['module'][$oldModuleID]; - $newParentID = $this->map['module'][$module->parent]; - $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec(); - } - return count($modules); - } - - /** - * Convert bugs. - * - * @access public - * @return int converted bugs count. - */ - public function convertBug() - { - $bugs = $this->dao - ->dbh($this->sourceDBH) - ->select(' - bugID AS id, - projectID AS product, - moduleID AS module, - bugTitle AS title, - bugSeverity AS severity, - bugPriority AS pri, - bugType AS type, - bugOS AS os, - bugBrowser AS browser, - bugMachine AS hardware, - howFound AS found, - reproSteps AS steps, - bugStatus AS status, - linkID AS linkBug, - duplicateID AS duplicateBug, - caseID AS `case`, - 1 AS caseVersion, - resultID AS result, - mailto, - openedBy, openedDate, openedBuild, - assignedTo, assignedDate, - resolvedBy, resolution, resolvedBuild, resolvedDate, - closedBy, closedDate, - lastEditedBy, lastEditedDate, - bugKeyword AS keywords - ') - ->from(BUGFREE_TABLE_BUGINFO) - ->where('isDroped')->eq(0) - ->orderBy('bugID') - ->fetchAll('id', $autoCompany = false); - foreach($bugs as $bugID => $bug) - { - /* Fix some fileds of bug. */ - $bugID = (int)$bugID; - unset($bug->id); - - if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed'; - if($bug->assignedTo == 'Active') $bug->assignedTo = ''; - - $bug->type = strtolower($bug->type); - $bug->found = strtolower($bug->found); - $bug->status = strtolower($bug->status); - $bug->os = strtolower($bug->os); - $bug->browser= strtolower($bug->browser); - $bug->steps = nl2br($bug->steps); - - if($bug->os == 'winvista') $bug->os = 'vista'; - if($bug->browser == 'firefox3.0') $bug->browser = 'firefox3'; - if($bug->browser == 'firefox2.0') $bug->browser = 'firefox2'; - if($bug->openedBuild == 'N/A') $bug->openedBuild = ''; - if(!$bug->case) $bug->caseVersion = 0; - - $bug->resolution = str_replace(' ', '', strtolower($bug->resolution)); - $bug->product = $this->map['product'][$bug->product]; - $bug->module = $this->map['module'][$bug->module]; - $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); - $this->map['bug'][$bugID] = $this->dao->lastInsertID(); - } - - /* Update duplicated bugs. */ - foreach($this->map['bug'] as $oldBugID => $newBugID) - { - $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec(); - } - return count($bugs); - } - - /** - * Convert cases. - * - * @access public - * @return int converted cases count. - */ - public function convertCase() - { - $cases = $this->dao - ->dbh($this->sourceDBH) - ->select(' - caseID AS id, - projectID AS product, - moduleID AS module, - caseTitle AS title, - caseSteps AS step, - casePriority AS pri, - caseType AS type, - caseStatus AS status, - caseMethod AS howRun, - casePlan AS stage, - openedBy, openedDate, - lastEditedBy, lastEditedDate, - scriptedBy, scriptedDate, scriptStatus, scriptLocation, - linkID AS linkCase, - casekeyword AS keywords, - 1 AS version, - bugID - ') - ->from(BUGFREE_TABLE_CASEINFO) - ->where('isDroped')->eq(0) - ->orderBy('caseID') - ->fetchAll('id', $autoCompany = false); - foreach($cases as $caseID => $case) - { - /* Fix fields of case. */ - $caseID = (int)$caseID; - $step = $case->step; - $bugs = explode(',', $case->bugID); - unset($case->id); - unset($case->step); - unset($case->bugID); - - $case->type = strtolower($case->type); - $case->status = strtolower($case->status); - $case->howRun = strtolower($case->howRun); - $case->stage = strtolower($case->stage); - - if($case->type == 'configuration') $case->type = 'config'; - if($case->type == 'setup') $case->type = 'install'; - if($case->type == 'functional') $case->type = 'feature'; - if($case->status == 'active') $case->status = 'normal'; - - /* Change product and module by zentao's product and module. */ - $case->product = $this->map['product'][$case->product]; - $case->module = $this->map['module'][$case->module]; - - /* Insert into case table. */ - $this->dao->dbh($this->dbh)->insert(TABLE_CASE)->data($case)->exec(); - $zentaoCaseID = $this->dao->lastInsertID(); - $this->map['case'][$caseID] = $zentaoCaseID; - - /* Insert into case step table. */ - $caseStep->case = $zentaoCaseID; - $caseStep->version = 1; - $caseStep->desc = $step; - $this->dao->dbh($this->dbh)->insert(TABLE_CASESTEP)->data($caseStep)->exec(); - - /* Update related bugs. */ - foreach($bugs as $bugID) - { - if(!isset($this->map['bug'][$bugID])) continue; - $zentaoBugID = $this->map['bug'][$bugID]; - $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('`case`')->eq($zentaoCaseID)->where('id')->eq($zentaoBugID)->limit(1)->exec(); - } - } - return count($cases); - } - - /** - * Convert results. - * - * @access public - * @return int converted results count. - */ - public function convertResult() - { - $results = $this->dao->dbh($this->sourceDBH) - ->select(' - resultID AS id, - caseID AS `case`, - resultValue AS caseResult, - 1 AS version, - openedDate as date, - bugID - ') - ->from(BUGFREE_TABLE_RESULTINFO) - ->orderBy('id') - ->fetchAll('id', $autoCompany = false); - foreach($results as $resultID => $result) - { - unset($result->id); - - /* The bug id of zentao. */ - $bugID = (int)$result->bugID; - $zentaoBugID = $this->map['bug'][$bugID]; - unset($result->bugID); - - /* Insert into test result table. */ - $this->dao->dbh($this->dbh)->insert(TABLE_TESTRESULT)->data($result)->exec(); - $zentaoResultID = $this->dao->lastInsertId(); - $this->map['result'][$resultID] = $zentaoResultID; - - /* Update result table. */ - $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('result')->eq($zentaoResultID)->where('id')->eq($zentaoBugID)->limit(1)->exec(); - } - return count($results); - } - - /** - * Convert actions. - * - * @access public - * @return int converted actions count. - */ - public function convertAction() - { - $actions = $this->dao - ->dbh($this->sourceDBH) - ->select("actionID AS id, - actionTarget AS objectType, - idValue AS objectID, - actionUser AS actor, - actionType AS action, - actionDate AS date, - actionNote AS comment - ") - ->from(BUGFREE_TABLE_ACTION) - ->where('actionTarget' != 'Result') - ->orderBy('actionID') - ->fetchAll('id', $autoComapny = false); - - foreach($actions as $actionID => $action) - { - $actionID = (int)$action->id; - unset($action->id); - $action->objectType = strtolower($action->objectType); - $action->action = strtolower($action->action); - $action->objectID = $this->map[$action->objectType][$action->objectID]; - - $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec(); - $this->map['action'][$actionID] = $this->dao->lastInsertID(); - } - return count($actions); - } - - /** - * Convert histories. - * - * @access public - * @return int the converted histories count. - */ - public function convertHistory() - { - $histories = $this->dao->dbh($this->sourceDBH) - ->select('actioID, actionField AS field, oldValue AS old, newValue AS new') - ->from(BUGFREE_TABLE_HISTORY) - ->orderBy('historyID') - ->fetchAll('', $autoCompany = false); - foreach($histories as $history) - { - $history->actionID = $this->map['action'][$history->actionID]; - $this->dao->dbh($this->dbh)->insert(TABLE_HISTORY)->data($history)->exec(); - } - } - - /** - * Convert attachments. - * - * @access public - * @return int the converted files count. - */ - public function convertFile() - { - $this->setPath(); - $files = $this->dao->dbh($this->sourceDBH) - ->select(" - actionID, - fileName AS pathname, - fileTitle AS title, - fileType AS extension, - fileSize AS size - ") - ->from(BUGFREE_TABLE_FILE) - ->orderBy('fileID') - ->fetchAll('', $autoCompany = false); - foreach($files as $file) - { - /* Get the actionID in zentao, to get file info. */ - $zentaoActionID = $this->map['action'][$file->actionID]; - $zentaoAction = $this->dao->dbh($this->dbh)->findById($zentaoActionID)->from(TABLE_ACTION)->fetch(); - $file->objectType = $zentaoAction->objectType; - $file->objectID = $zentaoAction->objectID; - $file->addedBy = $zentaoAction->actor; - $file->addedDate = $zentaoAction->date; - unset($file->actionID); - - /* Compute the file size. */ - if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024); - if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024); - - /* Insert into database. */ - $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); - - /* Copy file. */ - $soureFile = $this->filePath . $file->pathname; - if(!file_exists($soureFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); - continue; - } - $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; - $targetPath = dirname($targetFile); - if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); - if(!copy($soureFile, $targetFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); - } - } - return count($files); - } - - /** - * Clear the converted records. - * - * @access public - * @return void - */ - public function clear() - { - foreach($this->session->state as $table => $maxID) - { - $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); - } - } -} + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +class bugfree2ConvertModel extends bugfreeConvertModel +{ + /** + * Execute the converter. + * + * @access public + * @return array + */ + public function execute() + { + $this->clear(); + $this->setTable(); + $this->convertGroup(); + $result['users'] = $this->convertUser(); + $result['projects'] = $this->convertProject(); + $result['modules'] = $this->convertModule(); + $result['bugs'] = $this->convertBug(); + $result['cases'] = $this->convertCase(); + $result['results'] = $this->convertResult(); + $result['actions'] = $this->convertAction(); + $result['files'] = $this->convertFile(); + $this->dao->dbh($this->dbh); + $this->loadModel('tree')->fixModulePath(); + return $result; + } + + /** + * Set table names. + * + * @access public + * @return void + */ + public function setTable() + { + $dbPrefix = $this->post->dbPrefix; + define('BUGFREE_TABLE_OPTION', $dbPrefix . 'TestOptions'); + define('BUGFREE_TABLE_USER', $dbPrefix . 'TestUser'); + define('BUGFREE_TABLE_PROJECT', $dbPrefix . 'TestProject'); + define('BUGFREE_TABLE_MODULE', $dbPrefix . 'TestModule'); + define('BUGFREE_TABLE_BUGINFO', $dbPrefix . 'BugInfo'); + define('BUGFREE_TABLE_CASEINFO', $dbPrefix . 'CaseInfo'); + define('BUGFREE_TABLE_RESULTINFO', $dbPrefix . 'ResultInfo'); + define('BUGFREE_TABLE_ACTION', $dbPrefix . 'TestAction'); + define('BUGFREE_TABLE_FILE', $dbPrefix . 'TestFile'); + define('BUGFREE_TABLE_HISTORY', $dbPrefix . 'TestHistory'); + define('BUGFREE_TABLE_GROUP', $dbPrefix . 'TestGroup'); + } + + /** + * Get the version of bugfree2.x. + * + * @access public + * @return int + */ + public function getBugFreeVersion() + { + return $this->dao->dbh($this->sourceDBH) + ->select("optionValue as version")->from(BUGFREE_TABLE_OPTION) + ->where('OptionName')->eq('dbVersion') + ->fetch('version', $autoCompany = false); + + } + + /** + * Convert user. + * + * @access public + * @return int converted user count + */ + public function convertUser() + { + /* Get all user list. */ + $users = $this->dao + ->dbh($this->sourceDBH) + ->select("username AS account, userpassword AS password, realname, email, isDroped AS deleted") + ->from(BUGFREE_TABLE_USER) + ->orderBy('userID ASC') + ->fetchAll('account', $autoCompany = false); + + /* Insert into zentao. */ + $convertCount = 0; + foreach($users as $account => $user) + { + if(!$this->dao->dbh($this->dbh)->findByAccount($account)->from(TABLE_USER)->fetch('account')) + { + $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); + $convertCount ++; + } + else + { + self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $account); + } + } + return $convertCount; + } + + /** + * Convert groups. + * + * @access public + * @return void converted group count. + */ + public function convertGroup() + { + if(!$this->tableExists(BUGFREE_TABLE_GROUP)) return false; + $groups = $this->dao->dbh($this->sourceDBH) + ->select("groupID AS id, groupName AS name, groupUser AS users") + ->from(BUGFREE_TABLE_GROUP) + ->fetchAll('id', $autoCompany = false); + foreach($groups as $groupID => $group) + { + /* Fix the group data. */ + if($group->name == '[All Users]') continue; + $groupUsers = explode(',', $group->users); + unset($group->id); + unset($group->users); + + /* Insert into zentao's group table. */ + $this->dao->dbh($this->dbh)->insert(TABLE_GROUP)->data($group)->exec(); + $zentaoGroupID = $this->dao->lastInsertId(); + + /* Insert into zentao's usergroup table. */ + foreach($groupUsers as $account) + { + if(empty($account)) continue; + $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP) + ->set('`group`')->eq($zentaoGroupID) + ->set('account')->eq($account) + ->exec(); + } + } + } + + /** + * Convert projects. + * + * @access public + * @return int converted projects count. + */ + public function convertProject() + { + $projects = $this->dao->dbh($this->sourceDBH) + ->select("projectID AS id, projectName AS name, isDroped AS deleted") + ->from(BUGFREE_TABLE_PROJECT) + ->fetchAll('id', $autoComapny = false); + foreach($projects as $projectID => $project) + { + unset($project->id); + $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($project)->exec(); + $this->map['product'][$projectID] = $this->dao->lastInsertID(); + } + return count($projects); + } + + /** + * Convert modules. + * + * @access public + * @return int converted modules count. + */ + public function convertModule() + { + $this->map['module'][0] = 0; + $modules = $this->dao + ->dbh($this->sourceDBH) + ->select( + 'moduleID AS id, + moduleType as type, + projectID AS root, + moduleName AS name, + moduleGrade AS grade, + parentID AS parent, + displayOrder AS `order`') + ->from(BUGFREE_TABLE_MODULE) + ->orderBy('id ASC') + ->fetchAll('id', $autoCompany = false); + foreach($modules as $moduleID => $module) + { + $module->root = $this->map['product'][$module->root]; + $module->type = strtolower($module->type); + unset($module->id); + $this->dao->dbh($this->dbh)->insert(TABLE_MODULE)->data($module)->exec(); + $this->map['module'][$moduleID] = $this->dao->lastInsertID(); + } + + /* Update parent. */ + foreach($modules as $oldModuleID => $module) + { + $newModuleID = $this->map['module'][$oldModuleID]; + $newParentID = $this->map['module'][$module->parent]; + $this->dao->dbh($this->dbh)->update(TABLE_MODULE)->set('parent')->eq($newParentID)->where('id')->eq($newModuleID)->exec(); + } + return count($modules); + } + + /** + * Convert bugs. + * + * @access public + * @return int converted bugs count. + */ + public function convertBug() + { + $bugs = $this->dao + ->dbh($this->sourceDBH) + ->select(' + bugID AS id, + projectID AS product, + moduleID AS module, + bugTitle AS title, + bugSeverity AS severity, + bugPriority AS pri, + bugType AS type, + bugOS AS os, + bugBrowser AS browser, + bugMachine AS hardware, + howFound AS found, + reproSteps AS steps, + bugStatus AS status, + linkID AS linkBug, + duplicateID AS duplicateBug, + caseID AS `case`, + 1 AS caseVersion, + resultID AS result, + mailto, + openedBy, openedDate, openedBuild, + assignedTo, assignedDate, + resolvedBy, resolution, resolvedBuild, resolvedDate, + closedBy, closedDate, + lastEditedBy, lastEditedDate, + bugKeyword AS keywords + ') + ->from(BUGFREE_TABLE_BUGINFO) + ->where('isDroped')->eq(0) + ->orderBy('bugID') + ->fetchAll('id', $autoCompany = false); + foreach($bugs as $bugID => $bug) + { + /* Fix some fileds of bug. */ + $bugID = (int)$bugID; + unset($bug->id); + + if($bug->assignedTo == 'Closed') $bug->assignedTo = 'closed'; + if($bug->assignedTo == 'Active') $bug->assignedTo = ''; + + $bug->type = strtolower($bug->type); + $bug->found = strtolower($bug->found); + $bug->status = strtolower($bug->status); + $bug->os = strtolower($bug->os); + $bug->browser= strtolower($bug->browser); + $bug->steps = nl2br($bug->steps); + + if($bug->os == 'winvista') $bug->os = 'vista'; + if($bug->browser == 'firefox3.0') $bug->browser = 'firefox3'; + if($bug->browser == 'firefox2.0') $bug->browser = 'firefox2'; + if($bug->openedBuild == 'N/A') $bug->openedBuild = ''; + if(!$bug->case) $bug->caseVersion = 0; + + $bug->resolution = str_replace(' ', '', strtolower($bug->resolution)); + $bug->product = $this->map['product'][$bug->product]; + $bug->module = $this->map['module'][$bug->module]; + $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); + $this->map['bug'][$bugID] = $this->dao->lastInsertID(); + } + + /* Update duplicated bugs. */ + foreach($this->map['bug'] as $oldBugID => $newBugID) + { + $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('duplicateBug')->eq($newBugID)->where('duplicateBug')->eq($oldBugID)->exec(); + } + return count($bugs); + } + + /** + * Convert cases. + * + * @access public + * @return int converted cases count. + */ + public function convertCase() + { + $cases = $this->dao + ->dbh($this->sourceDBH) + ->select(' + caseID AS id, + projectID AS product, + moduleID AS module, + caseTitle AS title, + caseSteps AS step, + casePriority AS pri, + caseType AS type, + caseStatus AS status, + caseMethod AS howRun, + casePlan AS stage, + openedBy, openedDate, + lastEditedBy, lastEditedDate, + scriptedBy, scriptedDate, scriptStatus, scriptLocation, + linkID AS linkCase, + casekeyword AS keywords, + 1 AS version, + bugID + ') + ->from(BUGFREE_TABLE_CASEINFO) + ->where('isDroped')->eq(0) + ->orderBy('caseID') + ->fetchAll('id', $autoCompany = false); + foreach($cases as $caseID => $case) + { + /* Fix fields of case. */ + $caseID = (int)$caseID; + $step = $case->step; + $bugs = explode(',', $case->bugID); + unset($case->id); + unset($case->step); + unset($case->bugID); + + $case->type = strtolower($case->type); + $case->status = strtolower($case->status); + $case->howRun = strtolower($case->howRun); + $case->stage = strtolower($case->stage); + + if($case->type == 'configuration') $case->type = 'config'; + if($case->type == 'setup') $case->type = 'install'; + if($case->type == 'functional') $case->type = 'feature'; + if($case->status == 'active') $case->status = 'normal'; + + /* Change product and module by zentao's product and module. */ + $case->product = $this->map['product'][$case->product]; + $case->module = $this->map['module'][$case->module]; + + /* Insert into case table. */ + $this->dao->dbh($this->dbh)->insert(TABLE_CASE)->data($case)->exec(); + $zentaoCaseID = $this->dao->lastInsertID(); + $this->map['case'][$caseID] = $zentaoCaseID; + + /* Insert into case step table. */ + $caseStep->case = $zentaoCaseID; + $caseStep->version = 1; + $caseStep->desc = $step; + $this->dao->dbh($this->dbh)->insert(TABLE_CASESTEP)->data($caseStep)->exec(); + + /* Update related bugs. */ + foreach($bugs as $bugID) + { + if(!isset($this->map['bug'][$bugID])) continue; + $zentaoBugID = $this->map['bug'][$bugID]; + $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('`case`')->eq($zentaoCaseID)->where('id')->eq($zentaoBugID)->limit(1)->exec(); + } + } + return count($cases); + } + + /** + * Convert results. + * + * @access public + * @return int converted results count. + */ + public function convertResult() + { + $results = $this->dao->dbh($this->sourceDBH) + ->select(' + resultID AS id, + caseID AS `case`, + resultValue AS caseResult, + 1 AS version, + openedDate as date, + bugID + ') + ->from(BUGFREE_TABLE_RESULTINFO) + ->orderBy('id') + ->fetchAll('id', $autoCompany = false); + foreach($results as $resultID => $result) + { + unset($result->id); + + /* The bug id of zentao. */ + $bugID = (int)$result->bugID; + $zentaoBugID = $this->map['bug'][$bugID]; + unset($result->bugID); + + /* Insert into test result table. */ + $this->dao->dbh($this->dbh)->insert(TABLE_TESTRESULT)->data($result)->exec(); + $zentaoResultID = $this->dao->lastInsertId(); + $this->map['result'][$resultID] = $zentaoResultID; + + /* Update result table. */ + $this->dao->dbh($this->dbh)->update(TABLE_BUG)->set('result')->eq($zentaoResultID)->where('id')->eq($zentaoBugID)->limit(1)->exec(); + } + return count($results); + } + + /** + * Convert actions. + * + * @access public + * @return int converted actions count. + */ + public function convertAction() + { + $actions = $this->dao + ->dbh($this->sourceDBH) + ->select("actionID AS id, + actionTarget AS objectType, + idValue AS objectID, + actionUser AS actor, + actionType AS action, + actionDate AS date, + actionNote AS comment + ") + ->from(BUGFREE_TABLE_ACTION) + ->where('actionTarget' != 'Result') + ->orderBy('actionID') + ->fetchAll('id', $autoComapny = false); + + foreach($actions as $actionID => $action) + { + $actionID = (int)$action->id; + unset($action->id); + $action->objectType = strtolower($action->objectType); + $action->action = strtolower($action->action); + $action->objectID = $this->map[$action->objectType][$action->objectID]; + + $this->dao->dbh($this->dbh)->insert(TABLE_ACTION)->data($action)->exec(); + $this->map['action'][$actionID] = $this->dao->lastInsertID(); + } + return count($actions); + } + + /** + * Convert histories. + * + * @access public + * @return int the converted histories count. + */ + public function convertHistory() + { + $histories = $this->dao->dbh($this->sourceDBH) + ->select('actioID, actionField AS field, oldValue AS old, newValue AS new') + ->from(BUGFREE_TABLE_HISTORY) + ->orderBy('historyID') + ->fetchAll('', $autoCompany = false); + foreach($histories as $history) + { + $history->actionID = $this->map['action'][$history->actionID]; + $this->dao->dbh($this->dbh)->insert(TABLE_HISTORY)->data($history)->exec(); + } + } + + /** + * Convert attachments. + * + * @access public + * @return int the converted files count. + */ + public function convertFile() + { + $this->setPath(); + $files = $this->dao->dbh($this->sourceDBH) + ->select(" + actionID, + fileName AS pathname, + fileTitle AS title, + fileType AS extension, + fileSize AS size + ") + ->from(BUGFREE_TABLE_FILE) + ->orderBy('fileID') + ->fetchAll('', $autoCompany = false); + foreach($files as $file) + { + /* Get the actionID in zentao, to get file info. */ + $zentaoActionID = $this->map['action'][$file->actionID]; + $zentaoAction = $this->dao->dbh($this->dbh)->findById($zentaoActionID)->from(TABLE_ACTION)->fetch(); + $file->objectType = $zentaoAction->objectType; + $file->objectID = $zentaoAction->objectID; + $file->addedBy = $zentaoAction->actor; + $file->addedDate = $zentaoAction->date; + unset($file->actionID); + + /* Compute the file size. */ + if(strpos($file->size, 'KB')) $file->size = (int)(str_replace('KB', '', $file->size) * 1024); + if(strpos($file->size, 'MB')) $file->size = (int)(str_replace('MB', '', $file->size) * 1024 * 1024); + + /* Insert into database. */ + $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); + + /* Copy file. */ + $soureFile = $this->filePath . $file->pathname; + if(!file_exists($soureFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); + continue; + } + $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; + $targetPath = dirname($targetFile); + if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); + if(!copy($soureFile, $targetFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); + } + } + return count($files); + } + + /** + * Clear the converted records. + * + * @access public + * @return void + */ + public function clear() + { + foreach($this->session->state as $table => $maxID) + { + $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); + } + } +} diff --git a/module/convert/converter/redmine.php b/module/convert/converter/redmine.php index 464b6edfcb..50c1b0207a 100644 --- a/module/convert/converter/redmine.php +++ b/module/convert/converter/redmine.php @@ -1,88 +1,88 @@ - - * @package convert - * @version $Id $ - * @link http://www.zentao.net - */ -class redmineConvertModel extends convertModel -{ - public $map = array(); - public $filePath = ''; - static public $info = array(); - - /** - * Connect to db auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - parent::connectDB(); - } - - /** - * Check table. - * - * @access public - * @return bool - */ - public function checkTables() - { - return true; - } - - /** - * Check the install path. - * - * @access public - * @return bool - */ - public function checkPath() - { - $this->setPath(); - return file_exists($this->filePath); - } - - /** - * Set the path of attachments. - * - * @access public - * @return bool - */ - public function setPath() - { - $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'files' . $this->app->getPathFix(); - } - - /** - * Excute the convert. - * - * @param int $version - * @access public - * @return void - */ - public function execute($version) - { - } - - /** - * Clear rows added in converting. - * - * @access public - * @return void - */ - public function clear() - { - foreach($this->session->state as $table => $maxID) - { - $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); - } - } -} + + * @package convert + * @version $Id $ + * @link http://www.zentao.net + */ +class redmineConvertModel extends convertModel +{ + public $map = array(); + public $filePath = ''; + static public $info = array(); + + /** + * Connect to db auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + parent::connectDB(); + } + + /** + * Check table. + * + * @access public + * @return bool + */ + public function checkTables() + { + return true; + } + + /** + * Check the install path. + * + * @access public + * @return bool + */ + public function checkPath() + { + $this->setPath(); + return file_exists($this->filePath); + } + + /** + * Set the path of attachments. + * + * @access public + * @return bool + */ + public function setPath() + { + $this->filePath = realpath($this->post->installPath) . $this->app->getPathFix() . 'files' . $this->app->getPathFix(); + } + + /** + * Excute the convert. + * + * @param int $version + * @access public + * @return void + */ + public function execute($version) + { + } + + /** + * Clear rows added in converting. + * + * @access public + * @return void + */ + public function clear() + { + foreach($this->session->state as $table => $maxID) + { + $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); + } + } +} diff --git a/module/convert/converter/redmine1.1.php b/module/convert/converter/redmine1.1.php index 8ab99848c8..87fec9d407 100644 --- a/module/convert/converter/redmine1.1.php +++ b/module/convert/converter/redmine1.1.php @@ -1,822 +1,822 @@ - - * @package convert - * @version $Id $ - * @link http://www.zentao.net - */ -class redmine11ConvertModel extends redmineConvertModel -{ - static $convertGroupCount = 0; - static $convertUserCount = 0; - static $convertProductCount = 0; - static $convertProjectCount = 0; - static $convertStoryCount = 0; - static $convertTaskCount = 0; - static $convertBugCount = 0; - static $convertProductPlanCount = 0; - static $convertTeamCount = 0; - static $convertReleaseCount = 0; - static $convertBuildCount = 0; - static $convertDocLibCount = 0; - static $convertDocCount = 0; - static $convertFileCount = 0; - public $issueType; - - public function __construct($issueType) - { - parent::__construct(); - $this->issueType = $issueType; - } - /** - * Execute the converter. - * - * @access public - * @return array - */ - public function execute() - { - $this->clear(); - $this->setTable(); - $this->convertGroup(); - $this->convertUser(); - $this->convertUserGroup(); - $this->convertProduct(); - $this->convertProject(); - $this->convertBuildAndRelease(); - $this->convertProductPlan(); - $this->convertProjectProduct(); - $this->convertTeam(); - $this->convertDocLib(); - $this->convertDoc(); - $this->convertNews(); - $this->convertIssue(); - $this->convertFile(); - $this->dao->dbh($this->dbh); - $this->loadModel('tree')->fixModulePath(); - - $result['groups'] = self::$convertGroupCount; - $result['users'] = self::$convertUserCount ; - $result['products'] = self::$convertProductCount ; - $result['projects'] = self::$convertProjectCount ; - $result['stories'] = self::$convertStoryCount; - $result['tasks'] = self::$convertTaskCount ; - $result['bugs'] = self::$convertBugCount ; - $result['productPlans'] = self::$convertProductPlanCount; - $result['teams'] = self::$convertTeamCount; - $result['releases'] = self::$convertReleaseCount; - $result['builds'] = self::$convertBuildCount; - $result['docLibs'] = self::$convertDocLibCount ; - $result['docs'] = self::$convertDocCount; - $result['files'] = self::$convertFileCount; - return $result; - } - - /** - * Set table names. - * - * @access public - * @return void - */ - public function setTable() - { - //$dbPrefix = $this->post->dbPrefix; - $dbPrefix = ''; - define('REDMINE_TABLE_ATTACHMENTS', $dbPrefix . 'attachments'); - define('REDMINE_TABLE_AUTH_SOURCES', $dbPrefix . 'auth_sources'); - define('REDMINE_TABLE_BOARDS', $dbPrefix . 'boards'); - define('REDMINE_TABLE_CHANGES', $dbPrefix . 'changes'); - define('REDMINE_TABLE_CHANGESETS', $dbPrefix . 'changesets'); - define('REDMINE_TABLE_CHANGESETS_ISSUES', $dbPrefix . 'changesets_issues'); - define('REDMINE_TABLE_COMMENTS', $dbPrefix . 'comments'); - define('REDMINE_TABLE_CUSTOM_FIELDS', $dbPrefix . 'custom_fields'); - define('REDMINE_TABLE_CUSTOM_FIELDS_PROJECTS', $dbPrefix . 'custom_fields_projects'); - define('REDMINE_TABLE_CUSTOM_FIELDS_TRACKERS', $dbPrefix . 'custom_fields_trackers'); - define('REDMINE_TABLE_CUSTOM_VALUES', $dbPrefix . 'custom_values'); - define('REDMINE_TABLE_DOCUMENTS', $dbPrefix . 'documents'); - define('REDMINE_TABLE_ENABLED_MODULES', $dbPrefix . 'enabled_modules'); - define('REDMINE_TABLE_ENUMERATIONS', $dbPrefix . 'enumerations'); - define('REDMINE_TABLE_GROUPS_USERS', $dbPrefix . 'groups_users'); - define('REDMINE_TABLE_ISSUES', $dbPrefix . 'issues'); - define('REDMINE_TABLE_ISSUE_CATEGORIES', $dbPrefix . 'issue_categories'); - define('REDMINE_TABLE_ISSUE_RELATIONS', $dbPrefix . 'issue_relations'); - define('REDMINE_TABLE_ISSUE_STATUSES', $dbPrefix . 'issue_statuses'); - define('REDMINE_TABLE_JOURNALS', $dbPrefix . 'journals'); - define('REDMINE_TABLE_JOURNAL_DETAILS', $dbPrefix . 'journal_details'); - define('REDMINE_TABLE_MEMBERS', $dbPrefix . 'members'); - define('REDMINE_TABLE_MEMBER_ROLES', $dbPrefix . 'member_roles'); - define('REDMINE_TABLE_MESSAGES', $dbPrefix . 'messages'); - define('REDMINE_TABLE_NEWS', $dbPrefix . 'news'); - define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_ASSOCIATIONS', $dbPrefix . 'open_id_authentication_associations'); - define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_NONCES', $dbPrefix . 'open_id_authentication_nonces'); - define('REDMINE_TABLE_PROJECTS', $dbPrefix . 'projects'); - define('REDMINE_TABLE_PROJECTS_TRACKERS', $dbPrefix . 'projects_trackers'); - define('REDMINE_TABLE_QUERIES', $dbPrefix . 'queries'); - define('REDMINE_TABLE_REPOSITORIES', $dbPrefix . 'repositories'); - define('REDMINE_TABLE_ROLES', $dbPrefix . 'roles'); - define('REDMINE_TABLE_SCHEMA_MIGRATIONS', $dbPrefix . 'schema_migrations'); - define('REDMINE_TABLE_SETTINGS', $dbPrefix . 'settings'); - define('REDMINE_TABLE_TIME_ENTRIES', $dbPrefix . 'time_entries'); - define('REDMINE_TABLE_TOKENS', $dbPrefix . 'tokens'); - define('REDMINE_TABLE_TRACKERS', $dbPrefix . 'trackers'); - define('REDMINE_TABLE_USERS', $dbPrefix . 'users'); - define('REDMINE_TABLE_USER_PREFERENCES', $dbPrefix . 'user_preferences'); - define('REDMINE_TABLE_VERSIONS', $dbPrefix . 'versions'); - define('REDMINE_TABLE_WATCHERS', $dbPrefix . 'watchers'); - define('REDMINE_TABLE_WIKIS', $dbPrefix . 'wikis'); - define('REDMINE_TABLE_WIKI_CONTENTS', $dbPrefix . 'wiki_contents'); - define('REDMINE_TABLE_WIKI_CONTENT_VERSIONS', $dbPrefix . 'wiki_content_versions'); - define('REDMINE_TABLE_WIKI_PAGES', $dbPrefix . 'wiki_pages'); - define('REDMINE_TABLE_WIKI_REDIRECTS', $dbPrefix . 'wiki_redirects'); - define('REDMINE_TABLE_WORKFLOWS', $dbPrefix . 'workflows'); - } - - /** - * Convert groups. - * - * @access public - * @return void - */ - public function convertGroup() - { - /* Get group list */ - $groups = $this->dao->dbh($this->sourceDBH) - ->select("id, lastName AS name") - ->from(REDMINE_TABLE_USERS) - ->where('type')->eq('Group') - ->fetchAll('id', $autoCompany = false); - - $zentaoGroupNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_GROUP)->fetchPairs(); - $zentaoGroupIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_GROUP)->fetchPairs(); - - /* Insert into zentao */ - $convertCount = 0; - foreach($groups as $groupID =>$group) - { - unset($group->id); - if(in_array("$group->name", $zentaoGroupNames)) - { - self::$info['groups'][] = sprintf($this->lang->convert->errorGroupExists, $group->name); - $this->map['groups'][$groupID] = $zentaoGroupIDs[$group->name]; - } - else - { - $this->dao->dbh($this->dbh)->insert(TABLE_GROUP) - ->data($group)->exec(); - $this->map['groups'][$groupID] = $this->dao->lastInsertID(); - $convertCount ++; - } - } - self::$convertGroupCount += $convertCount; - } - - /** - * Convert users. - * - * @access public - * @return void - */ - public function convertUser() - { - /* Get user list. */ - $users = $this->dao->dbh($this->sourceDBH) - ->select("id, login AS account, firstname, lastname, mail as email") - ->from(REDMINE_TABLE_USERS) - ->where('type')->eq('User') - ->fetchAll('id', $autoCompany = false); - - $zentaoUserNames = $this->dao->dbh($this->dbh)->select('id, account')->from(TABLE_USER)->fetchPairs(); - $zentaoUserIDs = $this->dao->dbh($this->dbh)->select('account, id')->from(TABLE_USER)->fetchPairs(); - - /* Insert into zentao. */ - $convertCount = 0; - foreach($users as $id => $user) - { - if(in_array("$user->account", $zentaoUserNames)) - { - self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $user->account); - $this->map['users'][$id] = $zentaoUserIDs[$user->account]; - } - else - { - $user->password = md5('123456'); - $user->realname = $user->lastname . $user->firstname; - unset($user->id); - unset($user->lastname); - unset($user->firstname); - $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); - $this->map['users'][$id] = $this->dao->lastInsertID(); - $convertCount ++; - } - } - self::$convertUserCount += $convertCount; - } - - /** - * convert relationship between user and group. - * - * @access public - * @return void - */ - public function convertUserGroup() - { - $this->map['groups'][0] = 0; - /* Get relation between user and group list. */ - $userGroups = $this->dao->dbh($this->sourceDBH) - ->select("t1.group_id, t2.login as account") - ->from(REDMINE_TABLE_GROUPS_USERS)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id') - ->fetchAll('', $autoCompany = false); - - $zentaoUserGroups = $this->dao->dbh($this->dbh)->select('*')->from(TABLE_USERGROUP)->fetchAll(); - - /* Insert into zentao. */ - $userGroupExist = false; - foreach($userGroups as $userGroup) - { - $userGroup->group = $this->map['groups'][$userGroup->group_id]; - unset($userGroup->group_id); - foreach($zentaoUserGroups as $zentaoUserGroup) - { - if($userGroup->group == $zentaoUserGroup->group and $userGroup->account == $zentaoUserGroup->account) - { - $userGroupExist = true; - } - } - if($userGroupExist == false) - { - $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->data($userGroup)->exec(); - } - } - } - - /** - * convert products. - * - * @access public - * @return void - */ - public function convertProduct() - { - /* Get product list */ - $products = $this->dao->dbh($this->sourceDBH) - ->select("id, name, description as `desc`, created_on as createdDate") - ->from(REDMINE_TABLE_PROJECTS) - ->fetchAll('id', $autoComapny = false); - - /* Insert into zentao */ - foreach($products as $productID => $product) - { - unset($product->id); - $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($product)->exec(); - $this->map['products'][$productID] = $this->dao->lastInsertID(); - } - self::$convertProductCount += count($products); - } - - /** - * Convert projects. - * - * @access public - * @return void - */ - public function convertProject() - { - /* Get project list */ - $projects = $this->dao->dbh($this->sourceDBH) - ->select("id, name, project_id, description as `desc`, effective_date AS end") - ->from(REDMINE_TABLE_VERSIONS) - ->fetchAll('id', $autoComapny = false); - - /* Insert into zentao */ - foreach($projects as $projectID => $project) - { - $productID = $project->project_id; - unset($project->id); - unset($project->project_id); - $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec(); - $this->map['projects'][$productID][$projectID] = $this->dao->lastInsertID(); - $this->map['project'][$projectID] = $this->map['projects'][$productID][$projectID]; - } - - /* Create a same name project with product */ - foreach($this->map['products'] as $productID) - { - $project = $this->dao->dbh($this->dbh)->select('name')->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch(); - $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec(); - $this->map['projectOfProduct'][$productID] = $this->dao->lastinsertID(); - } - $convertCount = count($projects) + count($this->map['projectOfProduct']); - self::$convertProjectCount += $convertCount; - } - - /** - * convert builds and releases - * - * @access public - * @return void - */ - public function convertBuildAndRelease() - { - /* Get build list */ - $buildAndReleases = $this->dao->dbh($this->sourceDBH) - ->select("id, name, project_id, description as `desc`, effective_date AS date") - ->from(REDMINE_TABLE_VERSIONS) - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - $convertBuildsCount = 0; - $convertReleasesCount = 0; - $zentaoBuildNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_BUILD)->fetchPairs(); - $zentaoBuildIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_BUILD)->fetchPairs(); - $zentaoReleaseNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_RELEASE)->fetchPairs(); - $zentaoReleaseIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_RELEASE)->fetchPairs(); - foreach($buildAndReleases as $id => $buildAndRelease) - { - $buildAndRelease->project = $this->map['project'][$id]; - $buildAndRelease->product = $this->map['products'][$buildAndRelease->project_id]; - unset($buildAndRelease->id); - unset($buildAndRelease->project_id); - - if(in_array($buildAndRelease->name, $zentaoBuildNames)) - { - self::$info['builds'][] = sprintf($this->lang->convert->errorBuildExists, $buildAndRelease->name); - $buildAndRelease->build = $zentaoBuildIDs[$buildAndRelease->name]; - } - else - { - $this->dao->dbh($this->dbh)->insert(TABLE_BUILD)->data($buildAndRelease)->exec(); - $buildAndRelease->build = $this->dao->lastInsertID(); - $convertBuildsCount ++; - } - - unset($buildAndRelease->project); - if(in_array($buildAndRelease->name, $zentaoBuildNames)) - { - self::$info['releases'][] = sprintf($this->lang->convert->errorReleaseExists, $buildAndRelease->name); - } - else - { - $this->dao->dbh($this->dbh)->insert(TABLE_RELEASE)->data($buildAndRelease)->exec(); - $convertReleasesCount ++; - } - } - self::$convertBuildCount += $convertBuildsCount; - self::$convertReleaseCount += $convertReleasesCount; - } - - /** - * convert productPlans - * - * @access public - * @return void - */ - public function convertProductPlan() - { - /* Get productPlan list */ - $productPlans = $this->dao->dbh($this->sourceDBH) - ->select("id, name as title, project_id, description as `desc`, effective_date as end, created_on AS begin") - ->from(REDMINE_TABLE_VERSIONS) - ->fetchAll('id', $autoCompany = false); - /* Insert into zentao */ - foreach($productPlans as $id => $productPlan) - { - $productPlan->product = $this->map['products'][$productPlan->project_id]; - unset($productPlan->id); - unset($productPlan->project_id); - $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec(); - } - - /* Create a same plan with product */ - foreach($this->map['products'] as $productID) - { - $productPlan = $this->dao->dbh($this->dbh)->select("name as title, createdDate as begin")->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch(); - $productPlan->product = $productID; - $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec(); - $this->map['planOfProduct'][$productID] = $this->dao->lastinsertID(); - } - $convertCount = count($this->map['products']) + count($productPlans); - self::$convertProductPlanCount += $convertCount; - } - - /** - * convert relationship between project and product. - * - * @access public - * @return void - */ - public function convertProjectProduct() - { - foreach($this->map['projects'] as $productID => $projects) - { - foreach($projects as $projectID => $project) - { - $this->dao->dbh($this->dbh)->insert(TABLE_PROJECTPRODUCT) - ->set('project')->eq($project) - ->set('product')->eq($this->map['products'][$productID]) - ->exec(); - } - } - } - - /** - * convert teams. - * - * @access public - * @return void - */ - public function convertTeam() - { - /* Get team list */ - $teams = $this->dao->dbh($this->sourceDBH) - ->select("t2.login as account, t1.project_id, t1.created_on AS joinDate") - ->from(REDMINE_TABLE_MEMBERS)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id') - ->where('t2.type')->eq('User') - ->fetchAll('', $autoCompany = false); - - /* Insert into zentao */ - foreach($teams as $team) - { - $productID = $team->project_id; - unset($team->project_id); - foreach($this->map['projects'][$productID] as $projectID) - { - $team->project = $projectID; - $this->dao->dbh($this->dbh)->insert(TABLE_TEAM)->data($team)->exec(); - } - } - self::$convertTeamCount += count($teams); - } - - /** - * convert docLibs. - * - * @access public - * @return void - */ - public function convertDocLib() - { - /* Get docLib list */ - $docLibs = $this->dao->dbh($this->sourceDBH) - ->select("id, name")->from(REDMINE_TABLE_ENUMERATIONS) - ->where('type')->eq('DocumentCategory') - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($docLibs as $docLibID => $docLib) - { - unset($docLib->id); - $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($docLib)->exec(); - $this->map['docLibs'][$docLibID] = $this->dao->lastInsertID(); - } - self::$convertDocLibCount += count($docLibs); - } - - /** - * convert docs. - * - * @access public - * @return void - */ - public function convertDoc() - { - /* Get all docs */ - $docs = $this->dao->dbh($this->sourceDBH) - ->select("t1.id, t1.project_id AS product, t2.id AS lib, t1.title, t1.description AS content, t1.created_on AS addedDate") - ->from(REDMINE_TABLE_DOCUMENTS)->alias('t1') - ->leftjoin(REDMINE_TABLE_ENUMERATIONS)->alias('t2')->on('t1.category_id = t2.id') - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($docs as $docID => $doc) - { - unset($doc->id); - $doc->type = 'text'; - $doc->project = 0; - $doc->product = $this->map['products'][$doc->product]; - $doc->lib = $this->map['docLibs'][$doc->lib]; - $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec(); - $this->map['docs'][$docID] = $this->dao->lastInsertID(); - } - self::$convertDocCount += count($docs); - } - - /** - * convert news. - * - * @access public - * @return void - */ - public function convertNews() - { - /* Get news from redmine */ - $news = $this->dao->dbh($this->sourceDBH) - ->select("t1.project_id as product, t1.title, t1.summary as digest, t1.description as content, t2.login as addedBy, t1.created_on as addedDate") - ->from(REDMINE_TABLE_NEWS)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id') - ->fetchAll('', $autoCompany = false); - - /* Create a news docLib */ - $newLib->name = 'news'; - $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($newLib)->exec(); - $this->map['news'] = $this->dao->lastInsertID(); - self::$convertDocLibCount += 1; - - /* Insert into zentao */ - foreach($news as $new) - { - $new->product = $this->map['products'][$new->product]; - $new->project = 0; - $new->lib = $this->map['news']; - $new->type = 'text'; - - $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($new)->exec(); - } - self::$convertDocCount += count($news); - } - - /** - * convert issue - * - * @param array $aimTypes //aimTypes['issueTypeID'] = aimtype eg. aimTypes[1] = 'bug'; - * @param array $statusTypes //statusTypes['task']['statusTypeID'] = statusType eg. statusTypes['task'][1] = 'wait'; - * //statusTypes['bug']['statusTypeID'] = statusType eg. statusTypes['bug'][1] = 'active'; - * @param array $priTypes //priTypes['task']['priTypeID'] = priType; eg. priTypes['task'][1] = 1; - * @access public - * @return void - */ - public function convertIssue() - { - $aimTypes = $this->issueType->aimTypes; - $statusTypes = $this->issueType->statusTypes; - $priTypes = $this->issueType->priTypes; - - foreach($aimTypes as $issueType => $aimType) - { - if('story' == $aimType) - { - $this->convertStory($issueType, $statusTypes, $priTypes); - } - elseif('task' == $aimType) - { - $this->convertTask($issueType, $statusTypes, $priTypes); - } - else - { - $this->convertBug($issueType, $statusTypes, $priTypes); - } - } - } - - /** - * convert story - * - * @param array $issueType - * @param array $statusTypes - * @param array $priTypes - * @access public - * @return void - */ - public function convertStory($issueType, $statusTypes, $priTypes) - { - /* Get story list*/ - $stories = $this->dao->dbh($this->sourceDBH) - ->select("t1.id, t1.project_id as product, t1.subject as title, t1.description as spec, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate") - ->from(REDMINE_TABLE_ISSUES)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') - ->where('t1.tracker_id')->eq($issueType) - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($stories as $issueID => $story) - { - $storySpec->title = $story->title; - $storySpec->spec = $story->spec; - unset($story->id); - unset($story->spec); - - /* Insert story into table story */ - $story->product = $this->map['products'][$story->product]; - $story->module = 0; - $story->plan = $this->map['planOfProduct'][$story->product]; - $story->fromBug = 0; - $story->pri = $priTypes['story'][$story->pri]; - $story->status = $statusTypes['story'][$story->status]; - $story->toBug = 0; - $story->duplicateStory = 0; - $this->dao->dbh($this->dbh)->insert(TABLE_STORY)->data($story)->exec(); - $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); - $this->map['issueType'][$issueID] = 'story'; - - /* Insert data into table storySpec */ - $storySpec->story = $this->map['issueID'][$issueID]; - $storySpec->version = 1; - $this->dao->dbh($this->dbh)->insert(TABLE_STORYSPEC)->data($storySpec)->exec(); - } - self::$convertStoryCount += count($stories); - } - - /** - * convert task - * - * @param array $issueType - * @param array $statusTypes - * @param array $priTypes - * @access public - * @return void - */ - public function convertTask($issueType, $statusTypes, $priTypes) - { - /* Get task list */ - $tasks = $this->dao->dbh($this->sourceDBH) - ->select("t1.id, t1.project_id as product, t1.fixed_version_id as project, t1.subject as name, t1.description as `desc`, t1.due_date as deadline, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate") - ->from(REDMINE_TABLE_ISSUES)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') - ->where('t1.tracker_id')->eq($issueType) - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($tasks as $issueID => $task) - { - $task->story = 0; - $task->storyVersion = 0; - $task->type = 'misc'; - $task->pri = $priTypes['task'][$task->pri]; - $task->status = $statusTypes['task'][$task->status]; - if($task->project == 0) - { - $task->project = $this->map['projectOfProduct'][$task->product]; - } - else - { - $task->project = $this->map['project'][$task->project]; - } - unset($task->id); - unset($task->product); - $this->dao->dbh($this->dbh)->insert(TABLE_TASK)->data($task)->exec(); - $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); - $this->map['issueType'][$issueID] = 'task'; - } - self::$convertTaskCount += count($tasks); - } - - /** - * convert bug - * - * @param array $issueType - * @param array $statusTypes - * @param array $priTypes - * @access public - * @return void - */ - public function convertBug($issueType, $statusTypes, $priTypes) - { - /* Get bug list */ - $bugs = $this->dao->dbh($this->sourceDBH) - ->select("t1.id, t1.project_id as product, t1.fixed_version_id project, t1.subject as title, t1.description as steps, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.updated_on as lastEditedDate") - ->from(REDMINE_TABLE_ISSUES)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') - ->where('t1.tracker_id')->eq($issueType) - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($bugs as $issueID => $bug) - { - $bug->product = $this->map['products'][$bug->product]; - $bug->module = 0; - $bug->story = 0; - $bug->storyVersion = 1; - $bug->task = 0; - $bug->severity = 3; - $bug->type = 'others'; - $bug->status = $statusTypes['bug'][$bug->status]; - $bug->openedBuild = 'trunk'; - $bug->duplicateBug = 0; - $bug->case = 0; - $bug->caseVersion = 1; - $bug->result = 0; - if($bug->project == 0) - { - $bug->project = $this->map['projectOfProduct'][$bug->product]; - } - else - { - $bug->project = $this->map['project'][$bug->project]; - } - unset($bug->id); - $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); - $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); - $this->map['issueType'][$issueID] = 'bug'; - } - self::$convertBugCount += count($bugs); - } - - /** - * Convert attachments. - * - * @access public - * @return void - */ - public function convertFile() - { - $this->setPath(); - - /* Get file list */ - $files = $this->dao->dbh($this->sourceDBH) - ->select('t1.id, t1.container_id as objectID, t1.container_type as objectType, t1.filename as title, t1.disk_filename as pathname, t1.filesize as size, t2.login as addedBy, t1.created_on as addedDate, description') - ->from(REDMINE_TABLE_ATTACHMENTS)->alias('t1') - ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id') - ->fetchAll('id', $autoCompany = false); - - /* Insert into zentao */ - foreach($files as $fileID => $file) - { - if($file->description != '') - { - $file->title = $file->description; - unset($file->description); - } - else - { - unset($file->description); - } - - /* Transform objectType and objectID */ - if($file->objectType == 'Issue') - { - $file->objectType = $this->map['issueType'][$file->objectID]; - $file->objectID = $this->map['issueID'][$file->objectID]; - } - elseif($file->objectType == 'Document') - { - $file->objectType = 'doc' ; - $file->objectID = $this->map['docs'][$file->objectID]; - } - elseif($file->objectType == 'WikiPage') - { - continue; - } - elseif($file->objectType == 'Version') - { - $doc->project = $this->map['project'][$file->objectID]; - $doc = $this->dao->dbh($this->dbh)->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($doc->project)->fetch(); - $doc->lib = 'project'; - $doc->module = 0; - $doc->title = $file->title; - $doc->type = 'file'; - $doc->addedBy = $file->addedBy; - $doc->addedDate = $file->addedDate; - $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec(); - self::$convertDocCount += 1; - - $file->objectType = 'doc'; - $file->objectID = $this->dao->lastInsertID(); - } - - $pathname = pathinfo($file->pathname); - $file->extension = $pathname["extension"]; - unset($file->id); - - /* Insert into database. */ - $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); - - /* Copy file. */ - $soureFile = $this->filePath . $file->pathname; - if(!file_exists($soureFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); - continue; - } - $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; - $targetPath = dirname($targetFile); - if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); - if(!copy($soureFile, $targetFile)) - { - self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); - } - } - self::$convertFileCount += count($files); - } - - /** - * Clear the converted records. - * - * @access public - * @return void - */ - public function clear() - { - foreach($this->session->state as $table => $maxID) - { - $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); - } - } -} + + * @package convert + * @version $Id $ + * @link http://www.zentao.net + */ +class redmine11ConvertModel extends redmineConvertModel +{ + static $convertGroupCount = 0; + static $convertUserCount = 0; + static $convertProductCount = 0; + static $convertProjectCount = 0; + static $convertStoryCount = 0; + static $convertTaskCount = 0; + static $convertBugCount = 0; + static $convertProductPlanCount = 0; + static $convertTeamCount = 0; + static $convertReleaseCount = 0; + static $convertBuildCount = 0; + static $convertDocLibCount = 0; + static $convertDocCount = 0; + static $convertFileCount = 0; + public $issueType; + + public function __construct($issueType) + { + parent::__construct(); + $this->issueType = $issueType; + } + /** + * Execute the converter. + * + * @access public + * @return array + */ + public function execute() + { + $this->clear(); + $this->setTable(); + $this->convertGroup(); + $this->convertUser(); + $this->convertUserGroup(); + $this->convertProduct(); + $this->convertProject(); + $this->convertBuildAndRelease(); + $this->convertProductPlan(); + $this->convertProjectProduct(); + $this->convertTeam(); + $this->convertDocLib(); + $this->convertDoc(); + $this->convertNews(); + $this->convertIssue(); + $this->convertFile(); + $this->dao->dbh($this->dbh); + $this->loadModel('tree')->fixModulePath(); + + $result['groups'] = self::$convertGroupCount; + $result['users'] = self::$convertUserCount ; + $result['products'] = self::$convertProductCount ; + $result['projects'] = self::$convertProjectCount ; + $result['stories'] = self::$convertStoryCount; + $result['tasks'] = self::$convertTaskCount ; + $result['bugs'] = self::$convertBugCount ; + $result['productPlans'] = self::$convertProductPlanCount; + $result['teams'] = self::$convertTeamCount; + $result['releases'] = self::$convertReleaseCount; + $result['builds'] = self::$convertBuildCount; + $result['docLibs'] = self::$convertDocLibCount ; + $result['docs'] = self::$convertDocCount; + $result['files'] = self::$convertFileCount; + return $result; + } + + /** + * Set table names. + * + * @access public + * @return void + */ + public function setTable() + { + //$dbPrefix = $this->post->dbPrefix; + $dbPrefix = ''; + define('REDMINE_TABLE_ATTACHMENTS', $dbPrefix . 'attachments'); + define('REDMINE_TABLE_AUTH_SOURCES', $dbPrefix . 'auth_sources'); + define('REDMINE_TABLE_BOARDS', $dbPrefix . 'boards'); + define('REDMINE_TABLE_CHANGES', $dbPrefix . 'changes'); + define('REDMINE_TABLE_CHANGESETS', $dbPrefix . 'changesets'); + define('REDMINE_TABLE_CHANGESETS_ISSUES', $dbPrefix . 'changesets_issues'); + define('REDMINE_TABLE_COMMENTS', $dbPrefix . 'comments'); + define('REDMINE_TABLE_CUSTOM_FIELDS', $dbPrefix . 'custom_fields'); + define('REDMINE_TABLE_CUSTOM_FIELDS_PROJECTS', $dbPrefix . 'custom_fields_projects'); + define('REDMINE_TABLE_CUSTOM_FIELDS_TRACKERS', $dbPrefix . 'custom_fields_trackers'); + define('REDMINE_TABLE_CUSTOM_VALUES', $dbPrefix . 'custom_values'); + define('REDMINE_TABLE_DOCUMENTS', $dbPrefix . 'documents'); + define('REDMINE_TABLE_ENABLED_MODULES', $dbPrefix . 'enabled_modules'); + define('REDMINE_TABLE_ENUMERATIONS', $dbPrefix . 'enumerations'); + define('REDMINE_TABLE_GROUPS_USERS', $dbPrefix . 'groups_users'); + define('REDMINE_TABLE_ISSUES', $dbPrefix . 'issues'); + define('REDMINE_TABLE_ISSUE_CATEGORIES', $dbPrefix . 'issue_categories'); + define('REDMINE_TABLE_ISSUE_RELATIONS', $dbPrefix . 'issue_relations'); + define('REDMINE_TABLE_ISSUE_STATUSES', $dbPrefix . 'issue_statuses'); + define('REDMINE_TABLE_JOURNALS', $dbPrefix . 'journals'); + define('REDMINE_TABLE_JOURNAL_DETAILS', $dbPrefix . 'journal_details'); + define('REDMINE_TABLE_MEMBERS', $dbPrefix . 'members'); + define('REDMINE_TABLE_MEMBER_ROLES', $dbPrefix . 'member_roles'); + define('REDMINE_TABLE_MESSAGES', $dbPrefix . 'messages'); + define('REDMINE_TABLE_NEWS', $dbPrefix . 'news'); + define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_ASSOCIATIONS', $dbPrefix . 'open_id_authentication_associations'); + define('REDMINE_TABLE_OPEN_ID_AUTHENTICATION_NONCES', $dbPrefix . 'open_id_authentication_nonces'); + define('REDMINE_TABLE_PROJECTS', $dbPrefix . 'projects'); + define('REDMINE_TABLE_PROJECTS_TRACKERS', $dbPrefix . 'projects_trackers'); + define('REDMINE_TABLE_QUERIES', $dbPrefix . 'queries'); + define('REDMINE_TABLE_REPOSITORIES', $dbPrefix . 'repositories'); + define('REDMINE_TABLE_ROLES', $dbPrefix . 'roles'); + define('REDMINE_TABLE_SCHEMA_MIGRATIONS', $dbPrefix . 'schema_migrations'); + define('REDMINE_TABLE_SETTINGS', $dbPrefix . 'settings'); + define('REDMINE_TABLE_TIME_ENTRIES', $dbPrefix . 'time_entries'); + define('REDMINE_TABLE_TOKENS', $dbPrefix . 'tokens'); + define('REDMINE_TABLE_TRACKERS', $dbPrefix . 'trackers'); + define('REDMINE_TABLE_USERS', $dbPrefix . 'users'); + define('REDMINE_TABLE_USER_PREFERENCES', $dbPrefix . 'user_preferences'); + define('REDMINE_TABLE_VERSIONS', $dbPrefix . 'versions'); + define('REDMINE_TABLE_WATCHERS', $dbPrefix . 'watchers'); + define('REDMINE_TABLE_WIKIS', $dbPrefix . 'wikis'); + define('REDMINE_TABLE_WIKI_CONTENTS', $dbPrefix . 'wiki_contents'); + define('REDMINE_TABLE_WIKI_CONTENT_VERSIONS', $dbPrefix . 'wiki_content_versions'); + define('REDMINE_TABLE_WIKI_PAGES', $dbPrefix . 'wiki_pages'); + define('REDMINE_TABLE_WIKI_REDIRECTS', $dbPrefix . 'wiki_redirects'); + define('REDMINE_TABLE_WORKFLOWS', $dbPrefix . 'workflows'); + } + + /** + * Convert groups. + * + * @access public + * @return void + */ + public function convertGroup() + { + /* Get group list */ + $groups = $this->dao->dbh($this->sourceDBH) + ->select("id, lastName AS name") + ->from(REDMINE_TABLE_USERS) + ->where('type')->eq('Group') + ->fetchAll('id', $autoCompany = false); + + $zentaoGroupNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_GROUP)->fetchPairs(); + $zentaoGroupIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_GROUP)->fetchPairs(); + + /* Insert into zentao */ + $convertCount = 0; + foreach($groups as $groupID =>$group) + { + unset($group->id); + if(in_array("$group->name", $zentaoGroupNames)) + { + self::$info['groups'][] = sprintf($this->lang->convert->errorGroupExists, $group->name); + $this->map['groups'][$groupID] = $zentaoGroupIDs[$group->name]; + } + else + { + $this->dao->dbh($this->dbh)->insert(TABLE_GROUP) + ->data($group)->exec(); + $this->map['groups'][$groupID] = $this->dao->lastInsertID(); + $convertCount ++; + } + } + self::$convertGroupCount += $convertCount; + } + + /** + * Convert users. + * + * @access public + * @return void + */ + public function convertUser() + { + /* Get user list. */ + $users = $this->dao->dbh($this->sourceDBH) + ->select("id, login AS account, firstname, lastname, mail as email") + ->from(REDMINE_TABLE_USERS) + ->where('type')->eq('User') + ->fetchAll('id', $autoCompany = false); + + $zentaoUserNames = $this->dao->dbh($this->dbh)->select('id, account')->from(TABLE_USER)->fetchPairs(); + $zentaoUserIDs = $this->dao->dbh($this->dbh)->select('account, id')->from(TABLE_USER)->fetchPairs(); + + /* Insert into zentao. */ + $convertCount = 0; + foreach($users as $id => $user) + { + if(in_array("$user->account", $zentaoUserNames)) + { + self::$info['users'][] = sprintf($this->lang->convert->errorUserExists, $user->account); + $this->map['users'][$id] = $zentaoUserIDs[$user->account]; + } + else + { + $user->password = md5('123456'); + $user->realname = $user->lastname . $user->firstname; + unset($user->id); + unset($user->lastname); + unset($user->firstname); + $this->dao->dbh($this->dbh)->insert(TABLE_USER)->data($user)->exec(); + $this->map['users'][$id] = $this->dao->lastInsertID(); + $convertCount ++; + } + } + self::$convertUserCount += $convertCount; + } + + /** + * convert relationship between user and group. + * + * @access public + * @return void + */ + public function convertUserGroup() + { + $this->map['groups'][0] = 0; + /* Get relation between user and group list. */ + $userGroups = $this->dao->dbh($this->sourceDBH) + ->select("t1.group_id, t2.login as account") + ->from(REDMINE_TABLE_GROUPS_USERS)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id') + ->fetchAll('', $autoCompany = false); + + $zentaoUserGroups = $this->dao->dbh($this->dbh)->select('*')->from(TABLE_USERGROUP)->fetchAll(); + + /* Insert into zentao. */ + $userGroupExist = false; + foreach($userGroups as $userGroup) + { + $userGroup->group = $this->map['groups'][$userGroup->group_id]; + unset($userGroup->group_id); + foreach($zentaoUserGroups as $zentaoUserGroup) + { + if($userGroup->group == $zentaoUserGroup->group and $userGroup->account == $zentaoUserGroup->account) + { + $userGroupExist = true; + } + } + if($userGroupExist == false) + { + $this->dao->dbh($this->dbh)->insert(TABLE_USERGROUP)->data($userGroup)->exec(); + } + } + } + + /** + * convert products. + * + * @access public + * @return void + */ + public function convertProduct() + { + /* Get product list */ + $products = $this->dao->dbh($this->sourceDBH) + ->select("id, name, description as `desc`, created_on as createdDate") + ->from(REDMINE_TABLE_PROJECTS) + ->fetchAll('id', $autoComapny = false); + + /* Insert into zentao */ + foreach($products as $productID => $product) + { + unset($product->id); + $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCT)->data($product)->exec(); + $this->map['products'][$productID] = $this->dao->lastInsertID(); + } + self::$convertProductCount += count($products); + } + + /** + * Convert projects. + * + * @access public + * @return void + */ + public function convertProject() + { + /* Get project list */ + $projects = $this->dao->dbh($this->sourceDBH) + ->select("id, name, project_id, description as `desc`, effective_date AS end") + ->from(REDMINE_TABLE_VERSIONS) + ->fetchAll('id', $autoComapny = false); + + /* Insert into zentao */ + foreach($projects as $projectID => $project) + { + $productID = $project->project_id; + unset($project->id); + unset($project->project_id); + $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec(); + $this->map['projects'][$productID][$projectID] = $this->dao->lastInsertID(); + $this->map['project'][$projectID] = $this->map['projects'][$productID][$projectID]; + } + + /* Create a same name project with product */ + foreach($this->map['products'] as $productID) + { + $project = $this->dao->dbh($this->dbh)->select('name')->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch(); + $this->dao->dbh($this->dbh)->insert(TABLE_PROJECT)->data($project)->exec(); + $this->map['projectOfProduct'][$productID] = $this->dao->lastinsertID(); + } + $convertCount = count($projects) + count($this->map['projectOfProduct']); + self::$convertProjectCount += $convertCount; + } + + /** + * convert builds and releases + * + * @access public + * @return void + */ + public function convertBuildAndRelease() + { + /* Get build list */ + $buildAndReleases = $this->dao->dbh($this->sourceDBH) + ->select("id, name, project_id, description as `desc`, effective_date AS date") + ->from(REDMINE_TABLE_VERSIONS) + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + $convertBuildsCount = 0; + $convertReleasesCount = 0; + $zentaoBuildNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_BUILD)->fetchPairs(); + $zentaoBuildIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_BUILD)->fetchPairs(); + $zentaoReleaseNames = $this->dao->dbh($this->dbh)->select('id, name')->from(TABLE_RELEASE)->fetchPairs(); + $zentaoReleaseIDs = $this->dao->dbh($this->dbh)->select('name, id')->from(TABLE_RELEASE)->fetchPairs(); + foreach($buildAndReleases as $id => $buildAndRelease) + { + $buildAndRelease->project = $this->map['project'][$id]; + $buildAndRelease->product = $this->map['products'][$buildAndRelease->project_id]; + unset($buildAndRelease->id); + unset($buildAndRelease->project_id); + + if(in_array($buildAndRelease->name, $zentaoBuildNames)) + { + self::$info['builds'][] = sprintf($this->lang->convert->errorBuildExists, $buildAndRelease->name); + $buildAndRelease->build = $zentaoBuildIDs[$buildAndRelease->name]; + } + else + { + $this->dao->dbh($this->dbh)->insert(TABLE_BUILD)->data($buildAndRelease)->exec(); + $buildAndRelease->build = $this->dao->lastInsertID(); + $convertBuildsCount ++; + } + + unset($buildAndRelease->project); + if(in_array($buildAndRelease->name, $zentaoBuildNames)) + { + self::$info['releases'][] = sprintf($this->lang->convert->errorReleaseExists, $buildAndRelease->name); + } + else + { + $this->dao->dbh($this->dbh)->insert(TABLE_RELEASE)->data($buildAndRelease)->exec(); + $convertReleasesCount ++; + } + } + self::$convertBuildCount += $convertBuildsCount; + self::$convertReleaseCount += $convertReleasesCount; + } + + /** + * convert productPlans + * + * @access public + * @return void + */ + public function convertProductPlan() + { + /* Get productPlan list */ + $productPlans = $this->dao->dbh($this->sourceDBH) + ->select("id, name as title, project_id, description as `desc`, effective_date as end, created_on AS begin") + ->from(REDMINE_TABLE_VERSIONS) + ->fetchAll('id', $autoCompany = false); + /* Insert into zentao */ + foreach($productPlans as $id => $productPlan) + { + $productPlan->product = $this->map['products'][$productPlan->project_id]; + unset($productPlan->id); + unset($productPlan->project_id); + $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec(); + } + + /* Create a same plan with product */ + foreach($this->map['products'] as $productID) + { + $productPlan = $this->dao->dbh($this->dbh)->select("name as title, createdDate as begin")->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch(); + $productPlan->product = $productID; + $this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec(); + $this->map['planOfProduct'][$productID] = $this->dao->lastinsertID(); + } + $convertCount = count($this->map['products']) + count($productPlans); + self::$convertProductPlanCount += $convertCount; + } + + /** + * convert relationship between project and product. + * + * @access public + * @return void + */ + public function convertProjectProduct() + { + foreach($this->map['projects'] as $productID => $projects) + { + foreach($projects as $projectID => $project) + { + $this->dao->dbh($this->dbh)->insert(TABLE_PROJECTPRODUCT) + ->set('project')->eq($project) + ->set('product')->eq($this->map['products'][$productID]) + ->exec(); + } + } + } + + /** + * convert teams. + * + * @access public + * @return void + */ + public function convertTeam() + { + /* Get team list */ + $teams = $this->dao->dbh($this->sourceDBH) + ->select("t2.login as account, t1.project_id, t1.created_on AS joinDate") + ->from(REDMINE_TABLE_MEMBERS)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.user_id = t2.id') + ->where('t2.type')->eq('User') + ->fetchAll('', $autoCompany = false); + + /* Insert into zentao */ + foreach($teams as $team) + { + $productID = $team->project_id; + unset($team->project_id); + foreach($this->map['projects'][$productID] as $projectID) + { + $team->project = $projectID; + $this->dao->dbh($this->dbh)->insert(TABLE_TEAM)->data($team)->exec(); + } + } + self::$convertTeamCount += count($teams); + } + + /** + * convert docLibs. + * + * @access public + * @return void + */ + public function convertDocLib() + { + /* Get docLib list */ + $docLibs = $this->dao->dbh($this->sourceDBH) + ->select("id, name")->from(REDMINE_TABLE_ENUMERATIONS) + ->where('type')->eq('DocumentCategory') + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($docLibs as $docLibID => $docLib) + { + unset($docLib->id); + $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($docLib)->exec(); + $this->map['docLibs'][$docLibID] = $this->dao->lastInsertID(); + } + self::$convertDocLibCount += count($docLibs); + } + + /** + * convert docs. + * + * @access public + * @return void + */ + public function convertDoc() + { + /* Get all docs */ + $docs = $this->dao->dbh($this->sourceDBH) + ->select("t1.id, t1.project_id AS product, t2.id AS lib, t1.title, t1.description AS content, t1.created_on AS addedDate") + ->from(REDMINE_TABLE_DOCUMENTS)->alias('t1') + ->leftjoin(REDMINE_TABLE_ENUMERATIONS)->alias('t2')->on('t1.category_id = t2.id') + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($docs as $docID => $doc) + { + unset($doc->id); + $doc->type = 'text'; + $doc->project = 0; + $doc->product = $this->map['products'][$doc->product]; + $doc->lib = $this->map['docLibs'][$doc->lib]; + $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec(); + $this->map['docs'][$docID] = $this->dao->lastInsertID(); + } + self::$convertDocCount += count($docs); + } + + /** + * convert news. + * + * @access public + * @return void + */ + public function convertNews() + { + /* Get news from redmine */ + $news = $this->dao->dbh($this->sourceDBH) + ->select("t1.project_id as product, t1.title, t1.summary as digest, t1.description as content, t2.login as addedBy, t1.created_on as addedDate") + ->from(REDMINE_TABLE_NEWS)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id') + ->fetchAll('', $autoCompany = false); + + /* Create a news docLib */ + $newLib->name = 'news'; + $this->dao->dbh($this->dbh)->insert(TABLE_DOCLIB)->data($newLib)->exec(); + $this->map['news'] = $this->dao->lastInsertID(); + self::$convertDocLibCount += 1; + + /* Insert into zentao */ + foreach($news as $new) + { + $new->product = $this->map['products'][$new->product]; + $new->project = 0; + $new->lib = $this->map['news']; + $new->type = 'text'; + + $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($new)->exec(); + } + self::$convertDocCount += count($news); + } + + /** + * convert issue + * + * @param array $aimTypes //aimTypes['issueTypeID'] = aimtype eg. aimTypes[1] = 'bug'; + * @param array $statusTypes //statusTypes['task']['statusTypeID'] = statusType eg. statusTypes['task'][1] = 'wait'; + * //statusTypes['bug']['statusTypeID'] = statusType eg. statusTypes['bug'][1] = 'active'; + * @param array $priTypes //priTypes['task']['priTypeID'] = priType; eg. priTypes['task'][1] = 1; + * @access public + * @return void + */ + public function convertIssue() + { + $aimTypes = $this->issueType->aimTypes; + $statusTypes = $this->issueType->statusTypes; + $priTypes = $this->issueType->priTypes; + + foreach($aimTypes as $issueType => $aimType) + { + if('story' == $aimType) + { + $this->convertStory($issueType, $statusTypes, $priTypes); + } + elseif('task' == $aimType) + { + $this->convertTask($issueType, $statusTypes, $priTypes); + } + else + { + $this->convertBug($issueType, $statusTypes, $priTypes); + } + } + } + + /** + * convert story + * + * @param array $issueType + * @param array $statusTypes + * @param array $priTypes + * @access public + * @return void + */ + public function convertStory($issueType, $statusTypes, $priTypes) + { + /* Get story list*/ + $stories = $this->dao->dbh($this->sourceDBH) + ->select("t1.id, t1.project_id as product, t1.subject as title, t1.description as spec, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate") + ->from(REDMINE_TABLE_ISSUES)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') + ->where('t1.tracker_id')->eq($issueType) + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($stories as $issueID => $story) + { + $storySpec->title = $story->title; + $storySpec->spec = $story->spec; + unset($story->id); + unset($story->spec); + + /* Insert story into table story */ + $story->product = $this->map['products'][$story->product]; + $story->module = 0; + $story->plan = $this->map['planOfProduct'][$story->product]; + $story->fromBug = 0; + $story->pri = $priTypes['story'][$story->pri]; + $story->status = $statusTypes['story'][$story->status]; + $story->toBug = 0; + $story->duplicateStory = 0; + $this->dao->dbh($this->dbh)->insert(TABLE_STORY)->data($story)->exec(); + $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); + $this->map['issueType'][$issueID] = 'story'; + + /* Insert data into table storySpec */ + $storySpec->story = $this->map['issueID'][$issueID]; + $storySpec->version = 1; + $this->dao->dbh($this->dbh)->insert(TABLE_STORYSPEC)->data($storySpec)->exec(); + } + self::$convertStoryCount += count($stories); + } + + /** + * convert task + * + * @param array $issueType + * @param array $statusTypes + * @param array $priTypes + * @access public + * @return void + */ + public function convertTask($issueType, $statusTypes, $priTypes) + { + /* Get task list */ + $tasks = $this->dao->dbh($this->sourceDBH) + ->select("t1.id, t1.project_id as product, t1.fixed_version_id as project, t1.subject as name, t1.description as `desc`, t1.due_date as deadline, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.estimated_hours as estimate, t1.updated_on as lastEditedDate") + ->from(REDMINE_TABLE_ISSUES)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') + ->where('t1.tracker_id')->eq($issueType) + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($tasks as $issueID => $task) + { + $task->story = 0; + $task->storyVersion = 0; + $task->type = 'misc'; + $task->pri = $priTypes['task'][$task->pri]; + $task->status = $statusTypes['task'][$task->status]; + if($task->project == 0) + { + $task->project = $this->map['projectOfProduct'][$task->product]; + } + else + { + $task->project = $this->map['project'][$task->project]; + } + unset($task->id); + unset($task->product); + $this->dao->dbh($this->dbh)->insert(TABLE_TASK)->data($task)->exec(); + $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); + $this->map['issueType'][$issueID] = 'task'; + } + self::$convertTaskCount += count($tasks); + } + + /** + * convert bug + * + * @param array $issueType + * @param array $statusTypes + * @param array $priTypes + * @access public + * @return void + */ + public function convertBug($issueType, $statusTypes, $priTypes) + { + /* Get bug list */ + $bugs = $this->dao->dbh($this->sourceDBH) + ->select("t1.id, t1.project_id as product, t1.fixed_version_id project, t1.subject as title, t1.description as steps, t1.status_id as status, t2.login as assignedTo, t1.priority_id as pri, t3.login as openedBy, t1.created_on as openedDate, t1.updated_on as lastEditedDate") + ->from(REDMINE_TABLE_ISSUES)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.assigned_to_id = t2.id') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t3')->on('t1.author_id = t3.id') + ->where('t1.tracker_id')->eq($issueType) + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($bugs as $issueID => $bug) + { + $bug->product = $this->map['products'][$bug->product]; + $bug->module = 0; + $bug->story = 0; + $bug->storyVersion = 1; + $bug->task = 0; + $bug->severity = 3; + $bug->type = 'others'; + $bug->status = $statusTypes['bug'][$bug->status]; + $bug->openedBuild = 'trunk'; + $bug->duplicateBug = 0; + $bug->case = 0; + $bug->caseVersion = 1; + $bug->result = 0; + if($bug->project == 0) + { + $bug->project = $this->map['projectOfProduct'][$bug->product]; + } + else + { + $bug->project = $this->map['project'][$bug->project]; + } + unset($bug->id); + $this->dao->dbh($this->dbh)->insert(TABLE_BUG)->data($bug)->exec(); + $this->map['issueID'][$issueID] = $this->dao->lastInsertID(); + $this->map['issueType'][$issueID] = 'bug'; + } + self::$convertBugCount += count($bugs); + } + + /** + * Convert attachments. + * + * @access public + * @return void + */ + public function convertFile() + { + $this->setPath(); + + /* Get file list */ + $files = $this->dao->dbh($this->sourceDBH) + ->select('t1.id, t1.container_id as objectID, t1.container_type as objectType, t1.filename as title, t1.disk_filename as pathname, t1.filesize as size, t2.login as addedBy, t1.created_on as addedDate, description') + ->from(REDMINE_TABLE_ATTACHMENTS)->alias('t1') + ->leftJoin(REDMINE_TABLE_USERS)->alias('t2')->on('t1.author_id = t2.id') + ->fetchAll('id', $autoCompany = false); + + /* Insert into zentao */ + foreach($files as $fileID => $file) + { + if($file->description != '') + { + $file->title = $file->description; + unset($file->description); + } + else + { + unset($file->description); + } + + /* Transform objectType and objectID */ + if($file->objectType == 'Issue') + { + $file->objectType = $this->map['issueType'][$file->objectID]; + $file->objectID = $this->map['issueID'][$file->objectID]; + } + elseif($file->objectType == 'Document') + { + $file->objectType = 'doc' ; + $file->objectID = $this->map['docs'][$file->objectID]; + } + elseif($file->objectType == 'WikiPage') + { + continue; + } + elseif($file->objectType == 'Version') + { + $doc->project = $this->map['project'][$file->objectID]; + $doc = $this->dao->dbh($this->dbh)->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($doc->project)->fetch(); + $doc->lib = 'project'; + $doc->module = 0; + $doc->title = $file->title; + $doc->type = 'file'; + $doc->addedBy = $file->addedBy; + $doc->addedDate = $file->addedDate; + $this->dao->dbh($this->dbh)->insert(TABLE_DOC)->data($doc)->exec(); + self::$convertDocCount += 1; + + $file->objectType = 'doc'; + $file->objectID = $this->dao->lastInsertID(); + } + + $pathname = pathinfo($file->pathname); + $file->extension = $pathname["extension"]; + unset($file->id); + + /* Insert into database. */ + $this->dao->dbh($this->dbh)->insert(TABLE_FILE)->data($file)->exec(); + + /* Copy file. */ + $soureFile = $this->filePath . $file->pathname; + if(!file_exists($soureFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorFileNotExits, $soureFile); + continue; + } + $targetFile = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; + $targetPath = dirname($targetFile); + if(!is_dir($targetPath)) mkdir($targetPath, 0777, true); + if(!copy($soureFile, $targetFile)) + { + self::$info['files'][] = sprintf($this->lang->convert->errorCopyFailed, $targetFile); + } + } + self::$convertFileCount += count($files); + } + + /** + * Clear the converted records. + * + * @access public + * @return void + */ + public function clear() + { + foreach($this->session->state as $table => $maxID) + { + $this->dao->dbh($this->dbh)->delete()->from($table)->where('id')->gt($maxID)->exec(); + } + } +} diff --git a/module/convert/lang/en.php b/module/convert/lang/en.php index 9765c29932..e30b32019f 100644 --- a/module/convert/lang/en.php +++ b/module/convert/lang/en.php @@ -1,109 +1,109 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->convert->common = 'Import'; -$lang->convert->next = 'Next'; -$lang->convert->pre = 'Back'; -$lang->convert->reload = 'Reload'; -$lang->convert->error = 'Error '; - -$lang->convert->start = 'Begin import'; -$lang->convert->desc = <<Welcome to use this convert wizard which will help you to import other system data to ZenTaoPMS.

      -Importing is dangerous. Be sure to backup your database and other data files and sure nobody is using pms when importing. -EOT; - -$lang->convert->selectSource = 'Select source system and version'; -$lang->convert->source = 'Source system'; -$lang->convert->version = 'Version'; -$lang->convert->mustSelectSource = "Must select a source system"; - -$lang->convert->direction = 'Please select the direction of issue in Redmine'; -$lang->convert->questionTypeOfRedmine = 'Types of issue in Redmine'; -$lang->convert->aimTypeOfZentao = 'Aim type in Zentao'; - -$lang->convert->directionList['bug'] = 'Bug'; -$lang->convert->directionList['task'] = 'Task'; -$lang->convert->directionList['story'] = 'Story'; - -$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); -$lang->convert->sourceList['Redmine'] = array('Redmine_1_1' => '1.1'); - -$lang->convert->setting = 'Setting'; -$lang->convert->checkConfig = 'Check setting'; - -$lang->convert->ok = 'Check passed(√)'; -$lang->convert->fail = 'Check failed(×)'; - -$lang->convert->settingDB = 'Set database'; -$lang->convert->dbHost = 'Database server'; -$lang->convert->dbPort = 'Server port'; -$lang->convert->dbUser = 'Database user'; -$lang->convert->dbPassword = 'Database password'; -$lang->convert->dbName = '%s database'; -$lang->convert->dbCharset = '%s charset'; -$lang->convert->dbPrefix = '%s table prefix'; -$lang->convert->installPath = '%s installed path'; - -$lang->convert->checkDB = 'Database'; -$lang->convert->checkTable = 'Table'; -$lang->convert->checkPath = 'Installed path'; - -$lang->convert->execute = 'Execute import'; -$lang->convert->item = 'Imported items'; -$lang->convert->count = 'Count'; -$lang->convert->info = 'Info'; - -$lang->convert->bugfree->users = 'User'; -$lang->convert->bugfree->projects = 'Project'; -$lang->convert->bugfree->modules = 'Module'; -$lang->convert->bugfree->bugs = 'Bug'; -$lang->convert->bugfree->cases = 'Case'; -$lang->convert->bugfree->results = 'Result'; -$lang->convert->bugfree->actions = 'History'; -$lang->convert->bugfree->files = 'File'; - -$lang->convert->redmine->users = 'Users'; -$lang->convert->redmine->groups = 'Groups'; -$lang->convert->redmine->products = 'Products'; -$lang->convert->redmine->projects = 'Projects'; -$lang->convert->redmine->stories = 'Stories'; -$lang->convert->redmine->tasks = 'Tasks'; -$lang->convert->redmine->bugs = 'Bugs'; -$lang->convert->redmine->productPlans = 'ProductPlans'; -$lang->convert->redmine->teams = 'Teams'; -$lang->convert->redmine->releases = 'Releases'; -$lang->convert->redmine->builds = 'Builds'; -$lang->convert->redmine->docLibs = 'DocLibs'; -$lang->convert->redmine->docs = 'Docs'; -$lang->convert->redmine->files = 'files'; - -$lang->convert->errorConnectDB = 'Connect to database server failed.'; -$lang->convert->errorFileNotExits = 'File %s not exits.'; -$lang->convert->errorUserExists = 'User %s exits already.'; -$lang->convert->errorGroupExists = 'Group %s exits already.'; -$lang->convert->errorBuildExists = 'Build %s exits already.'; -$lang->convert->errorReleaseExists = 'Release %s exits already.'; -$lang->convert->errorCopyFailed = 'file %s copy failed.'; - -$lang->convert->setParam = 'Please set params'; - -$lang->convert->aimType = 'Issue types goto'; -$lang->convert->statusType->bug = 'Status types goto(status of Bug)'; -$lang->convert->statusType->story = 'Status types goto(status of story)'; -$lang->convert->statusType->task = 'Status types goto(status of task)'; -$lang->convert->priType->bug = 'Priority types goto(priority of Bug)'; -$lang->convert->priType->story = 'Priority types goto(priority of story)'; -$lang->convert->priType->task = 'Priority types goto(priority of task)'; - -$lang->convert->issue->redmine = 'Redmine'; -$lang->convert->issue->zentao = 'ZenTao'; -$lang->convert->issue->goto = 'Goto'; + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->convert->common = 'Import'; +$lang->convert->next = 'Next'; +$lang->convert->pre = 'Back'; +$lang->convert->reload = 'Reload'; +$lang->convert->error = 'Error '; + +$lang->convert->start = 'Begin import'; +$lang->convert->desc = <<Welcome to use this convert wizard which will help you to import other system data to ZenTaoPMS.

      +Importing is dangerous. Be sure to backup your database and other data files and sure nobody is using pms when importing. +EOT; + +$lang->convert->selectSource = 'Select source system and version'; +$lang->convert->source = 'Source system'; +$lang->convert->version = 'Version'; +$lang->convert->mustSelectSource = "Must select a source system"; + +$lang->convert->direction = 'Please select the direction of issue in Redmine'; +$lang->convert->questionTypeOfRedmine = 'Types of issue in Redmine'; +$lang->convert->aimTypeOfZentao = 'Aim type in Zentao'; + +$lang->convert->directionList['bug'] = 'Bug'; +$lang->convert->directionList['task'] = 'Task'; +$lang->convert->directionList['story'] = 'Story'; + +$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); +$lang->convert->sourceList['Redmine'] = array('Redmine_1_1' => '1.1'); + +$lang->convert->setting = 'Setting'; +$lang->convert->checkConfig = 'Check setting'; + +$lang->convert->ok = 'Check passed(√)'; +$lang->convert->fail = 'Check failed(×)'; + +$lang->convert->settingDB = 'Set database'; +$lang->convert->dbHost = 'Database server'; +$lang->convert->dbPort = 'Server port'; +$lang->convert->dbUser = 'Database user'; +$lang->convert->dbPassword = 'Database password'; +$lang->convert->dbName = '%s database'; +$lang->convert->dbCharset = '%s charset'; +$lang->convert->dbPrefix = '%s table prefix'; +$lang->convert->installPath = '%s installed path'; + +$lang->convert->checkDB = 'Database'; +$lang->convert->checkTable = 'Table'; +$lang->convert->checkPath = 'Installed path'; + +$lang->convert->execute = 'Execute import'; +$lang->convert->item = 'Imported items'; +$lang->convert->count = 'Count'; +$lang->convert->info = 'Info'; + +$lang->convert->bugfree->users = 'User'; +$lang->convert->bugfree->projects = 'Project'; +$lang->convert->bugfree->modules = 'Module'; +$lang->convert->bugfree->bugs = 'Bug'; +$lang->convert->bugfree->cases = 'Case'; +$lang->convert->bugfree->results = 'Result'; +$lang->convert->bugfree->actions = 'History'; +$lang->convert->bugfree->files = 'File'; + +$lang->convert->redmine->users = 'Users'; +$lang->convert->redmine->groups = 'Groups'; +$lang->convert->redmine->products = 'Products'; +$lang->convert->redmine->projects = 'Projects'; +$lang->convert->redmine->stories = 'Stories'; +$lang->convert->redmine->tasks = 'Tasks'; +$lang->convert->redmine->bugs = 'Bugs'; +$lang->convert->redmine->productPlans = 'ProductPlans'; +$lang->convert->redmine->teams = 'Teams'; +$lang->convert->redmine->releases = 'Releases'; +$lang->convert->redmine->builds = 'Builds'; +$lang->convert->redmine->docLibs = 'DocLibs'; +$lang->convert->redmine->docs = 'Docs'; +$lang->convert->redmine->files = 'files'; + +$lang->convert->errorConnectDB = 'Connect to database server failed.'; +$lang->convert->errorFileNotExits = 'File %s not exits.'; +$lang->convert->errorUserExists = 'User %s exits already.'; +$lang->convert->errorGroupExists = 'Group %s exits already.'; +$lang->convert->errorBuildExists = 'Build %s exits already.'; +$lang->convert->errorReleaseExists = 'Release %s exits already.'; +$lang->convert->errorCopyFailed = 'file %s copy failed.'; + +$lang->convert->setParam = 'Please set params'; + +$lang->convert->aimType = 'Issue types goto'; +$lang->convert->statusType->bug = 'Status types goto(status of Bug)'; +$lang->convert->statusType->story = 'Status types goto(status of story)'; +$lang->convert->statusType->task = 'Status types goto(status of task)'; +$lang->convert->priType->bug = 'Priority types goto(priority of Bug)'; +$lang->convert->priType->story = 'Priority types goto(priority of story)'; +$lang->convert->priType->task = 'Priority types goto(priority of task)'; + +$lang->convert->issue->redmine = 'Redmine'; +$lang->convert->issue->zentao = 'ZenTao'; +$lang->convert->issue->goto = 'Goto'; diff --git a/module/convert/lang/zh-cn.php b/module/convert/lang/zh-cn.php index 229020eaf6..fc24c9a19b 100644 --- a/module/convert/lang/zh-cn.php +++ b/module/convert/lang/zh-cn.php @@ -1,109 +1,109 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->convert->common = '从其他系统导入'; -$lang->convert->next = '下一步'; -$lang->convert->pre = '返回'; -$lang->convert->reload = '刷新'; -$lang->convert->error = '错误 '; - -$lang->convert->start = '开始转换'; -$lang->convert->desc = <<欢迎使用系统转换向导,本程序会帮助您将其他系统的数据转换到禅道项目管理系统中。

      -转换存在一定的风险,转换之前,我们强烈建议您备份数据库及相应的数据文件,并保证转换的时候,没有其他人进行操作。 -EOT; - -$lang->convert->selectSource = '选择来源系统及版本'; -$lang->convert->source = '来源系统'; -$lang->convert->version = '版本'; -$lang->convert->mustSelectSource = "必须选择一个来源。"; - -$lang->convert->direction = '请选择项目问题转换方向'; -$lang->convert->questionTypeOfRedmine = 'Redmine中问题类型'; -$lang->convert->aimTypeOfZentao = '转化为Zentao中的类型'; - -$lang->convert->directionList['bug'] = 'Bug'; -$lang->convert->directionList['task'] = '任务'; -$lang->convert->directionList['story'] = '需求'; - -$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); -$lang->convert->sourceList['Redmine'] = array('Redmine_1.1' => '1.1'); - -$lang->convert->setting = '设置'; -$lang->convert->checkConfig = '检查配置'; - -$lang->convert->ok = '检查通过(√)'; -$lang->convert->fail = '检查失败(×)'; - -$lang->convert->settingDB = '设置数据库'; -$lang->convert->dbHost = '数据库服务器'; -$lang->convert->dbPort = '服务器端口'; -$lang->convert->dbUser = '数据库用户名'; -$lang->convert->dbPassword = '数据库密码'; -$lang->convert->dbName = '%s使用的库'; -$lang->convert->dbCharset = '%s数据库编码'; -$lang->convert->dbPrefix = '%s表前缀'; -$lang->convert->installPath = '%s安装的根目录'; - -$lang->convert->checkDB = '数据库'; -$lang->convert->checkTable = '表'; -$lang->convert->checkPath = '安装路径'; - -$lang->convert->execute = '执行转换'; -$lang->convert->item = '转换项'; -$lang->convert->count = '转换数量'; -$lang->convert->info = '转换信息'; - -$lang->convert->bugfree->users = '用户'; -$lang->convert->bugfree->projects = '项目'; -$lang->convert->bugfree->modules = '模块'; -$lang->convert->bugfree->bugs = 'Bug'; -$lang->convert->bugfree->cases = '测试用例'; -$lang->convert->bugfree->results = '测试结果'; -$lang->convert->bugfree->actions = '历史记录'; -$lang->convert->bugfree->files = '附件'; - -$lang->convert->redmine->users = '用户'; -$lang->convert->redmine->groups = '用户分组'; -$lang->convert->redmine->products = '产品'; -$lang->convert->redmine->projects = '项目'; -$lang->convert->redmine->stories = '需求'; -$lang->convert->redmine->tasks = '任务'; -$lang->convert->redmine->bugs = 'Bug'; -$lang->convert->redmine->productPlans = '产品计划'; -$lang->convert->redmine->teams = '团队'; -$lang->convert->redmine->releases = '发布'; -$lang->convert->redmine->builds = 'Build'; -$lang->convert->redmine->docLibs = '文档库'; -$lang->convert->redmine->docs = '文档'; -$lang->convert->redmine->files = '附件'; - -$lang->convert->errorConnectDB = '数据库连接失败 '; -$lang->convert->errorFileNotExits = '文件 %s 不存在'; -$lang->convert->errorUserExists = '用户 %s 已存在'; -$lang->convert->errorGroupExists = '分组 %s 已存在'; -$lang->convert->errorBuildExists = 'Build %s 已存在'; -$lang->convert->errorReleaseExists = '发布 %s 已存在'; -$lang->convert->errorCopyFailed = '文件 %s 拷贝失败'; - -$lang->convert->setParam = '请设置转换参数'; - -$lang->convert->aimType = '问题类型转换'; -$lang->convert->statusType->bug = '状态类型转换(Bug状态)'; -$lang->convert->statusType->story = '状态类型转换(Story状态)'; -$lang->convert->statusType->task = '状态类型转换(Task状态)'; -$lang->convert->priType->bug = '优先级类型转换(Bug状态)'; -$lang->convert->priType->story = '优先级类型转换(Story状态)'; -$lang->convert->priType->task = '优先级类型转换(Task状态)'; - -$lang->convert->issue->redmine = 'Redmine'; -$lang->convert->issue->zentao = '禅道'; -$lang->convert->issue->goto = '转换为'; + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->convert->common = '从其他系统导入'; +$lang->convert->next = '下一步'; +$lang->convert->pre = '返回'; +$lang->convert->reload = '刷新'; +$lang->convert->error = '错误 '; + +$lang->convert->start = '开始转换'; +$lang->convert->desc = <<欢迎使用系统转换向导,本程序会帮助您将其他系统的数据转换到禅道项目管理系统中。

      +转换存在一定的风险,转换之前,我们强烈建议您备份数据库及相应的数据文件,并保证转换的时候,没有其他人进行操作。 +EOT; + +$lang->convert->selectSource = '选择来源系统及版本'; +$lang->convert->source = '来源系统'; +$lang->convert->version = '版本'; +$lang->convert->mustSelectSource = "必须选择一个来源。"; + +$lang->convert->direction = '请选择项目问题转换方向'; +$lang->convert->questionTypeOfRedmine = 'Redmine中问题类型'; +$lang->convert->aimTypeOfZentao = '转化为Zentao中的类型'; + +$lang->convert->directionList['bug'] = 'Bug'; +$lang->convert->directionList['task'] = '任务'; +$lang->convert->directionList['story'] = '需求'; + +$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); +$lang->convert->sourceList['Redmine'] = array('Redmine_1.1' => '1.1'); + +$lang->convert->setting = '设置'; +$lang->convert->checkConfig = '检查配置'; + +$lang->convert->ok = '检查通过(√)'; +$lang->convert->fail = '检查失败(×)'; + +$lang->convert->settingDB = '设置数据库'; +$lang->convert->dbHost = '数据库服务器'; +$lang->convert->dbPort = '服务器端口'; +$lang->convert->dbUser = '数据库用户名'; +$lang->convert->dbPassword = '数据库密码'; +$lang->convert->dbName = '%s使用的库'; +$lang->convert->dbCharset = '%s数据库编码'; +$lang->convert->dbPrefix = '%s表前缀'; +$lang->convert->installPath = '%s安装的根目录'; + +$lang->convert->checkDB = '数据库'; +$lang->convert->checkTable = '表'; +$lang->convert->checkPath = '安装路径'; + +$lang->convert->execute = '执行转换'; +$lang->convert->item = '转换项'; +$lang->convert->count = '转换数量'; +$lang->convert->info = '转换信息'; + +$lang->convert->bugfree->users = '用户'; +$lang->convert->bugfree->projects = '项目'; +$lang->convert->bugfree->modules = '模块'; +$lang->convert->bugfree->bugs = 'Bug'; +$lang->convert->bugfree->cases = '测试用例'; +$lang->convert->bugfree->results = '测试结果'; +$lang->convert->bugfree->actions = '历史记录'; +$lang->convert->bugfree->files = '附件'; + +$lang->convert->redmine->users = '用户'; +$lang->convert->redmine->groups = '用户分组'; +$lang->convert->redmine->products = '产品'; +$lang->convert->redmine->projects = '项目'; +$lang->convert->redmine->stories = '需求'; +$lang->convert->redmine->tasks = '任务'; +$lang->convert->redmine->bugs = 'Bug'; +$lang->convert->redmine->productPlans = '产品计划'; +$lang->convert->redmine->teams = '团队'; +$lang->convert->redmine->releases = '发布'; +$lang->convert->redmine->builds = 'Build'; +$lang->convert->redmine->docLibs = '文档库'; +$lang->convert->redmine->docs = '文档'; +$lang->convert->redmine->files = '附件'; + +$lang->convert->errorConnectDB = '数据库连接失败 '; +$lang->convert->errorFileNotExits = '文件 %s 不存在'; +$lang->convert->errorUserExists = '用户 %s 已存在'; +$lang->convert->errorGroupExists = '分组 %s 已存在'; +$lang->convert->errorBuildExists = 'Build %s 已存在'; +$lang->convert->errorReleaseExists = '发布 %s 已存在'; +$lang->convert->errorCopyFailed = '文件 %s 拷贝失败'; + +$lang->convert->setParam = '请设置转换参数'; + +$lang->convert->aimType = '问题类型转换'; +$lang->convert->statusType->bug = '状态类型转换(Bug状态)'; +$lang->convert->statusType->story = '状态类型转换(Story状态)'; +$lang->convert->statusType->task = '状态类型转换(Task状态)'; +$lang->convert->priType->bug = '优先级类型转换(Bug状态)'; +$lang->convert->priType->story = '优先级类型转换(Story状态)'; +$lang->convert->priType->task = '优先级类型转换(Task状态)'; + +$lang->convert->issue->redmine = 'Redmine'; +$lang->convert->issue->zentao = '禅道'; +$lang->convert->issue->goto = '转换为'; diff --git a/module/convert/lang/zh-tw.php b/module/convert/lang/zh-tw.php index 606f4ae112..4aca518687 100644 --- a/module/convert/lang/zh-tw.php +++ b/module/convert/lang/zh-tw.php @@ -1,109 +1,109 @@ - - * @package convert - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->convert->common = '從其他系統導入'; -$lang->convert->next = '下一步'; -$lang->convert->pre = '返回'; -$lang->convert->reload = '刷新'; -$lang->convert->error = '錯誤 '; - -$lang->convert->start = '開始轉換'; -$lang->convert->desc = <<歡迎使用系統轉換嚮導,本程序會幫助您將其他系統的數據轉換到禪道項目管理系統中。

      -轉換存在一定的風險,轉換之前,我們強烈建議您備份資料庫及相應的數據檔案,並保證轉換的時候,沒有其他人進行操作。 -EOT; - -$lang->convert->selectSource = '選擇來源系統及版本'; -$lang->convert->source = '來源系統'; -$lang->convert->version = '版本'; -$lang->convert->mustSelectSource = "必須選擇一個來源。"; - -$lang->convert->direction = '請選擇項目問題轉換方向'; -$lang->convert->questionTypeOfRedmine = 'Redmine中問題類型'; -$lang->convert->aimTypeOfZentao = '轉化為Zentao中的類型'; - -$lang->convert->directionList['bug'] = 'Bug'; -$lang->convert->directionList['task'] = '任務'; -$lang->convert->directionList['story'] = '需求'; - -$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); -$lang->convert->sourceList['Redmine'] = array('Redmine_1.1' => '1.1'); - -$lang->convert->setting = '設置'; -$lang->convert->checkConfig = '檢查配置'; - -$lang->convert->ok = '檢查通過(√)'; -$lang->convert->fail = '檢查失敗(×)'; - -$lang->convert->settingDB = '設置資料庫'; -$lang->convert->dbHost = '資料庫伺服器'; -$lang->convert->dbPort = '伺服器連接埠'; -$lang->convert->dbUser = '資料庫用戶名'; -$lang->convert->dbPassword = '資料庫密碼'; -$lang->convert->dbName = '%s使用的庫'; -$lang->convert->dbCharset = '%s資料庫編碼'; -$lang->convert->dbPrefix = '%s表首碼'; -$lang->convert->installPath = '%s安裝的根目錄'; - -$lang->convert->checkDB = '資料庫'; -$lang->convert->checkTable = '表'; -$lang->convert->checkPath = '安裝路徑'; - -$lang->convert->execute = '執行轉換'; -$lang->convert->item = '轉換項'; -$lang->convert->count = '轉換數量'; -$lang->convert->info = '轉換信息'; - -$lang->convert->bugfree->users = '用戶'; -$lang->convert->bugfree->projects = '項目'; -$lang->convert->bugfree->modules = '模組'; -$lang->convert->bugfree->bugs = 'Bug'; -$lang->convert->bugfree->cases = '測試用例'; -$lang->convert->bugfree->results = '測試結果'; -$lang->convert->bugfree->actions = '歷史記錄'; -$lang->convert->bugfree->files = '附件'; - -$lang->convert->redmine->users = '用戶'; -$lang->convert->redmine->groups = '用戶分組'; -$lang->convert->redmine->products = '產品'; -$lang->convert->redmine->projects = '項目'; -$lang->convert->redmine->stories = '需求'; -$lang->convert->redmine->tasks = '任務'; -$lang->convert->redmine->bugs = 'Bug'; -$lang->convert->redmine->productPlans = '產品計劃'; -$lang->convert->redmine->teams = '團隊'; -$lang->convert->redmine->releases = '發佈'; -$lang->convert->redmine->builds = 'Build'; -$lang->convert->redmine->docLibs = '文檔庫'; -$lang->convert->redmine->docs = '文檔'; -$lang->convert->redmine->files = '附件'; - -$lang->convert->errorConnectDB = '資料庫連接失敗 '; -$lang->convert->errorFileNotExits = '檔案 %s 不存在'; -$lang->convert->errorUserExists = '用戶 %s 已存在'; -$lang->convert->errorGroupExists = '分組 %s 已存在'; -$lang->convert->errorBuildExists = 'Build %s 已存在'; -$lang->convert->errorReleaseExists = '發佈 %s 已存在'; -$lang->convert->errorCopyFailed = '檔案 %s 拷貝失敗'; - -$lang->convert->setParam = '請設置轉換參數'; - -$lang->convert->aimType = '問題類型轉換'; -$lang->convert->statusType->bug = '狀態類型轉換(Bug狀態)'; -$lang->convert->statusType->story = '狀態類型轉換(Story狀態)'; -$lang->convert->statusType->task = '狀態類型轉換(Task狀態)'; -$lang->convert->priType->bug = '優先順序類型轉換(Bug狀態)'; -$lang->convert->priType->story = '優先順序類型轉換(Story狀態)'; -$lang->convert->priType->task = '優先順序類型轉換(Task狀態)'; - -$lang->convert->issue->redmine = 'Redmine'; -$lang->convert->issue->zentao = '禪道'; -$lang->convert->issue->goto = '轉換為'; + + * @package convert + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->convert->common = '從其他系統導入'; +$lang->convert->next = '下一步'; +$lang->convert->pre = '返回'; +$lang->convert->reload = '刷新'; +$lang->convert->error = '錯誤 '; + +$lang->convert->start = '開始轉換'; +$lang->convert->desc = <<歡迎使用系統轉換嚮導,本程序會幫助您將其他系統的數據轉換到禪道項目管理系統中。

      +轉換存在一定的風險,轉換之前,我們強烈建議您備份資料庫及相應的數據檔案,並保證轉換的時候,沒有其他人進行操作。 +EOT; + +$lang->convert->selectSource = '選擇來源系統及版本'; +$lang->convert->source = '來源系統'; +$lang->convert->version = '版本'; +$lang->convert->mustSelectSource = "必須選擇一個來源。"; + +$lang->convert->direction = '請選擇項目問題轉換方向'; +$lang->convert->questionTypeOfRedmine = 'Redmine中問題類型'; +$lang->convert->aimTypeOfZentao = '轉化為Zentao中的類型'; + +$lang->convert->directionList['bug'] = 'Bug'; +$lang->convert->directionList['task'] = '任務'; +$lang->convert->directionList['story'] = '需求'; + +$lang->convert->sourceList['BugFree'] = array('bugfree_1' => '1.x', 'bugfree_2' => '2.x'); +$lang->convert->sourceList['Redmine'] = array('Redmine_1.1' => '1.1'); + +$lang->convert->setting = '設置'; +$lang->convert->checkConfig = '檢查配置'; + +$lang->convert->ok = '檢查通過(√)'; +$lang->convert->fail = '檢查失敗(×)'; + +$lang->convert->settingDB = '設置資料庫'; +$lang->convert->dbHost = '資料庫伺服器'; +$lang->convert->dbPort = '伺服器連接埠'; +$lang->convert->dbUser = '資料庫用戶名'; +$lang->convert->dbPassword = '資料庫密碼'; +$lang->convert->dbName = '%s使用的庫'; +$lang->convert->dbCharset = '%s資料庫編碼'; +$lang->convert->dbPrefix = '%s表首碼'; +$lang->convert->installPath = '%s安裝的根目錄'; + +$lang->convert->checkDB = '資料庫'; +$lang->convert->checkTable = '表'; +$lang->convert->checkPath = '安裝路徑'; + +$lang->convert->execute = '執行轉換'; +$lang->convert->item = '轉換項'; +$lang->convert->count = '轉換數量'; +$lang->convert->info = '轉換信息'; + +$lang->convert->bugfree->users = '用戶'; +$lang->convert->bugfree->projects = '項目'; +$lang->convert->bugfree->modules = '模組'; +$lang->convert->bugfree->bugs = 'Bug'; +$lang->convert->bugfree->cases = '測試用例'; +$lang->convert->bugfree->results = '測試結果'; +$lang->convert->bugfree->actions = '歷史記錄'; +$lang->convert->bugfree->files = '附件'; + +$lang->convert->redmine->users = '用戶'; +$lang->convert->redmine->groups = '用戶分組'; +$lang->convert->redmine->products = '產品'; +$lang->convert->redmine->projects = '項目'; +$lang->convert->redmine->stories = '需求'; +$lang->convert->redmine->tasks = '任務'; +$lang->convert->redmine->bugs = 'Bug'; +$lang->convert->redmine->productPlans = '產品計劃'; +$lang->convert->redmine->teams = '團隊'; +$lang->convert->redmine->releases = '發佈'; +$lang->convert->redmine->builds = 'Build'; +$lang->convert->redmine->docLibs = '文檔庫'; +$lang->convert->redmine->docs = '文檔'; +$lang->convert->redmine->files = '附件'; + +$lang->convert->errorConnectDB = '資料庫連接失敗 '; +$lang->convert->errorFileNotExits = '檔案 %s 不存在'; +$lang->convert->errorUserExists = '用戶 %s 已存在'; +$lang->convert->errorGroupExists = '分組 %s 已存在'; +$lang->convert->errorBuildExists = 'Build %s 已存在'; +$lang->convert->errorReleaseExists = '發佈 %s 已存在'; +$lang->convert->errorCopyFailed = '檔案 %s 拷貝失敗'; + +$lang->convert->setParam = '請設置轉換參數'; + +$lang->convert->aimType = '問題類型轉換'; +$lang->convert->statusType->bug = '狀態類型轉換(Bug狀態)'; +$lang->convert->statusType->story = '狀態類型轉換(Story狀態)'; +$lang->convert->statusType->task = '狀態類型轉換(Task狀態)'; +$lang->convert->priType->bug = '優先順序類型轉換(Bug狀態)'; +$lang->convert->priType->story = '優先順序類型轉換(Story狀態)'; +$lang->convert->priType->task = '優先順序類型轉換(Task狀態)'; + +$lang->convert->issue->redmine = 'Redmine'; +$lang->convert->issue->zentao = '禪道'; +$lang->convert->issue->goto = '轉換為'; diff --git a/module/convert/model.php b/module/convert/model.php index 3965851ef7..507c41841f 100644 --- a/module/convert/model.php +++ b/module/convert/model.php @@ -1,94 +1,94 @@ - - * @package convert - * @version $Id$ - * @link http://www.zentao.net - */ -?> -post->dbHost}; port={$this->post->dbPort};dbname={$this->post->dbName}"; - try - { - $dbh = new PDO($dsn, $this->post->dbUser, $this->post->dbPassword); - $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); - $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $dbh->exec("SET NAMES {$this->post->dbCharset}"); - $this->sourceDBH = $dbh; - return $dbh; - } - catch (PDOException $exception) - { - return $exception->getMessage(); - } - } - - /** - * Check database exits or not. - * - * @access public - * @return bool - */ - public function dbExists() - { - $sql = "SHOW DATABASES like '{$this->post->db->name}'"; - return $this->dbh->query($sql)->fetch(); - } - - /** - * Check table exits or not. - * - * @access public - * @return bool - */ - public function tableExists($table) - { - $sql = "SHOW tables like '$table'"; - return $this->dbh->query($sql)->fetch(); - } - - /** - * Save the max id of every table. Thus when we convert again, when can delete id larger then the saved max id. - * - * @access public - * @return void - */ - public function saveState() - { - /* Get user defined tables. */ - $constants = get_defined_constants(true); - $userConstants = $constants['user']; - - /* These tables needn't save. */ - unset($userConstants['TABLE_BURN']); - unset($userConstants['TABLE_GROUPPRIV']); - unset($userConstants['TABLE_PROJECTPRODUCT']); - unset($userConstants['TABLE_PROJECTSTORY']); - unset($userConstants['TABLE_STORYSPEC']); - unset($userConstants['TABLE_TEAM']); - unset($userConstants['TABLE_USERGROUP']); - - /* Get max id of every table. */ - foreach($userConstants as $key => $value) - { - if(strpos($key, 'TABLE') === false) continue; - if($key == 'TABLE_COMPANY') continue; - $state[$value] = (int)$this->dao->select('MAX(id) AS id')->from($value)->fetch('id'); - } - $this->session->set('state', $state); - } -} + + * @package convert + * @version $Id$ + * @link http://www.zentao.net + */ +?> +post->dbHost}; port={$this->post->dbPort};dbname={$this->post->dbName}"; + try + { + $dbh = new PDO($dsn, $this->post->dbUser, $this->post->dbPassword); + $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); + $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $dbh->exec("SET NAMES {$this->post->dbCharset}"); + $this->sourceDBH = $dbh; + return $dbh; + } + catch (PDOException $exception) + { + return $exception->getMessage(); + } + } + + /** + * Check database exits or not. + * + * @access public + * @return bool + */ + public function dbExists() + { + $sql = "SHOW DATABASES like '{$this->post->db->name}'"; + return $this->dbh->query($sql)->fetch(); + } + + /** + * Check table exits or not. + * + * @access public + * @return bool + */ + public function tableExists($table) + { + $sql = "SHOW tables like '$table'"; + return $this->dbh->query($sql)->fetch(); + } + + /** + * Save the max id of every table. Thus when we convert again, when can delete id larger then the saved max id. + * + * @access public + * @return void + */ + public function saveState() + { + /* Get user defined tables. */ + $constants = get_defined_constants(true); + $userConstants = $constants['user']; + + /* These tables needn't save. */ + unset($userConstants['TABLE_BURN']); + unset($userConstants['TABLE_GROUPPRIV']); + unset($userConstants['TABLE_PROJECTPRODUCT']); + unset($userConstants['TABLE_PROJECTSTORY']); + unset($userConstants['TABLE_STORYSPEC']); + unset($userConstants['TABLE_TEAM']); + unset($userConstants['TABLE_USERGROUP']); + + /* Get max id of every table. */ + foreach($userConstants as $key => $value) + { + if(strpos($key, 'TABLE') === false) continue; + if($key == 'TABLE_COMPANY') continue; + $state[$value] = (int)$this->dao->select('MAX(id) AS id')->from($value)->fetch('id'); + } + $this->session->set('state', $state); + } +} diff --git a/module/convert/view/checkconfig.html.php b/module/convert/view/checkconfig.html.php index c6585684bb..f9ffd9d97f 100644 --- a/module/convert/view/checkconfig.html.php +++ b/module/convert/view/checkconfig.html.php @@ -1,29 +1,29 @@ - - * @package convert - * @version $Id$ - */ -?> - -
      '> - - - -
      convert->checkConfig . $lang->colon . strtoupper($source);?>
      -post->dbHost); -echo html::hidden('dbPort', $this->post->dbPort); -echo html::hidden('dbUser', $this->post->dbUser); -echo html::hidden('dbPassword', $this->post->dbPassword); -echo html::hidden('dbName', $this->post->dbName); -echo html::hidden('dbCharset', $this->post->dbCharset); -echo html::hidden('dbPrefix', $this->post->dbPrefix); -echo html::hidden('installPath',$this->post->installPath); -?> -
      - + + * @package convert + * @version $Id$ + */ +?> + +
      '> + + + +
      convert->checkConfig . $lang->colon . strtoupper($source);?>
      +post->dbHost); +echo html::hidden('dbPort', $this->post->dbPort); +echo html::hidden('dbUser', $this->post->dbUser); +echo html::hidden('dbPassword', $this->post->dbPassword); +echo html::hidden('dbName', $this->post->dbName); +echo html::hidden('dbCharset', $this->post->dbCharset); +echo html::hidden('dbPrefix', $this->post->dbPrefix); +echo html::hidden('installPath',$this->post->installPath); +?> +
      + diff --git a/module/convert/view/execute.html.php b/module/convert/view/execute.html.php index 08c19d0419..6667ec2f3a 100644 --- a/module/convert/view/execute.html.php +++ b/module/convert/view/execute.html.php @@ -1,18 +1,18 @@ - - * @package convert - * @version $Id$ - */ -?> - - - - -
      convert->execute . $lang->colon . strtoupper($source);?>
      - - + + * @package convert + * @version $Id$ + */ +?> + + + + +
      convert->execute . $lang->colon . strtoupper($source);?>
      + + diff --git a/module/convert/view/index.html.php b/module/convert/view/index.html.php index 00c8ed0f58..f1743268bd 100644 --- a/module/convert/view/index.html.php +++ b/module/convert/view/index.html.php @@ -1,18 +1,18 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - - - -
      convert->common;?>
      convert->desc);?>

      createLink('convert', 'selectsource'), $lang->convert->start);?>

      - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + + + +
      convert->common;?>
      convert->desc);?>

      createLink('convert', 'selectsource'), $lang->convert->start);?>

      + diff --git a/module/convert/view/selectsource.html.php b/module/convert/view/selectsource.html.php index 7364692b33..8a3a1bab7d 100644 --- a/module/convert/view/selectsource.html.php +++ b/module/convert/view/selectsource.html.php @@ -1,31 +1,31 @@ - - * @package convert - * @version $Id$ - */ -?> - -
      '> - - - - - - - convert->sourceList as $name => $versions):?> - - - - - - - - -
      convert->selectSource;?>
      convert->source;?>convert->version;?>
      -
      - + + * @package convert + * @version $Id$ + */ +?> + +
      '> + + + + + + + convert->sourceList as $name => $versions):?> + + + + + + + + +
      convert->selectSource;?>
      convert->source;?>convert->version;?>
      +
      + diff --git a/module/convert/view/setconfig.html.php b/module/convert/view/setconfig.html.php index 5fc9ea0402..f2b4621078 100644 --- a/module/convert/view/setconfig.html.php +++ b/module/convert/view/setconfig.html.php @@ -1,23 +1,23 @@ - - * @package convert - * @version $Id$ - */ -?> - -
      '> - - - - - - -
      convert->setting . $lang->colon . strtoupper($source);?>
      - -
      - + + * @package convert + * @version $Id$ + */ +?> + +
      '> + + + + + + +
      convert->setting . $lang->colon . strtoupper($source);?>
      + +
      + diff --git a/module/dept/control.php b/module/dept/control.php index 68fca6cd2d..0c1c256a97 100644 --- a/module/dept/control.php +++ b/module/dept/control.php @@ -1,101 +1,101 @@ - - * @package dept - * @version $Id$ - * @link http://www.zentao.net - */ -class dept extends control -{ - const NEW_CHILD_COUNT = 5; - - /** - * Construct function, set menu. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('company')->setMenu(); - } - - /** - * Browse a department. - * - * @param int $deptID - * @access public - * @return void - */ - public function browse($deptID = 0) - { - $header['title'] = $this->lang->dept->manage . $this->lang->colon . $this->app->company->name; - $position[] = $this->lang->dept->manage; - - $parentDepts = $this->dept->getParents($deptID); - $this->view->header = $header; - $this->view->position = $position; - $this->view->deptID = $deptID; - $this->view->depts = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptmodel', 'createManageLink')); - $this->view->parentDepts = $parentDepts; - $this->view->sons = $this->dept->getSons($deptID); - $this->display(); - } - - /** - * Update the departments order. - * - * @access public - * @return void - */ - public function updateOrder() - { - if(!empty($_POST)) - { - $this->dept->updateOrder($_POST['orders']); - die(js::reload('parent')); - } - } - - /** - * Manage childs. - * - * @access public - * @return void - */ - public function manageChild() - { - if(!empty($_POST)) - { - $this->dept->manageChild($_POST['parentDeptID'], $_POST['depts']); - die(js::reload('parent')); - } - } - - /** - * Delete a department. - * - * @param int $deptID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($deptID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->dept->confirmDelete, $this->createLink('dept', 'delete', "deptID=$deptID&confirm=yes")); - exit; - } - else - { - $this->dept->delete($deptID); - die(js::reload('parent')); - } - } -} + + * @package dept + * @version $Id$ + * @link http://www.zentao.net + */ +class dept extends control +{ + const NEW_CHILD_COUNT = 5; + + /** + * Construct function, set menu. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('company')->setMenu(); + } + + /** + * Browse a department. + * + * @param int $deptID + * @access public + * @return void + */ + public function browse($deptID = 0) + { + $header['title'] = $this->lang->dept->manage . $this->lang->colon . $this->app->company->name; + $position[] = $this->lang->dept->manage; + + $parentDepts = $this->dept->getParents($deptID); + $this->view->header = $header; + $this->view->position = $position; + $this->view->deptID = $deptID; + $this->view->depts = $this->dept->getTreeMenu($rooteDeptID = 0, array('deptmodel', 'createManageLink')); + $this->view->parentDepts = $parentDepts; + $this->view->sons = $this->dept->getSons($deptID); + $this->display(); + } + + /** + * Update the departments order. + * + * @access public + * @return void + */ + public function updateOrder() + { + if(!empty($_POST)) + { + $this->dept->updateOrder($_POST['orders']); + die(js::reload('parent')); + } + } + + /** + * Manage childs. + * + * @access public + * @return void + */ + public function manageChild() + { + if(!empty($_POST)) + { + $this->dept->manageChild($_POST['parentDeptID'], $_POST['depts']); + die(js::reload('parent')); + } + } + + /** + * Delete a department. + * + * @param int $deptID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($deptID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->dept->confirmDelete, $this->createLink('dept', 'delete', "deptID=$deptID&confirm=yes")); + exit; + } + else + { + $this->dept->delete($deptID); + die(js::reload('parent')); + } + } +} diff --git a/module/dept/lang/en.php b/module/dept/lang/en.php index 8254579652..00d716d8b6 100644 --- a/module/dept/lang/en.php +++ b/module/dept/lang/en.php @@ -1,23 +1,23 @@ - - * @package dept - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->dept->common = 'Department'; -$lang->dept->add = "Add"; -$lang->dept->addChild = "Add child department"; -$lang->dept->manageChild = "Child deprtment"; -$lang->dept->delete = "Delete"; -$lang->dept->browse = "Manage"; -$lang->dept->manage = "Manage"; -$lang->dept->updateOrder = "Update order"; -$lang->dept->users = "Users"; - -$lang->dept->saveButton = " Save (S) "; -$lang->dept->confirmDelete = "Are you sure to delete this department?"; + + * @package dept + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->dept->common = 'Department'; +$lang->dept->add = "Add"; +$lang->dept->addChild = "Add child department"; +$lang->dept->manageChild = "Child deprtment"; +$lang->dept->delete = "Delete"; +$lang->dept->browse = "Manage"; +$lang->dept->manage = "Manage"; +$lang->dept->updateOrder = "Update order"; +$lang->dept->users = "Users"; + +$lang->dept->saveButton = " Save (S) "; +$lang->dept->confirmDelete = "Are you sure to delete this department?"; diff --git a/module/dept/lang/zh-cn.php b/module/dept/lang/zh-cn.php index 3c0adf855c..b5e808f4e4 100644 --- a/module/dept/lang/zh-cn.php +++ b/module/dept/lang/zh-cn.php @@ -1,23 +1,23 @@ - - * @package dept - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->dept->common = '部门结构'; -$lang->dept->add = "添加"; -$lang->dept->addChild = "添加下级部门"; -$lang->dept->manageChild = "下级部门"; -$lang->dept->delete = "删除部门"; -$lang->dept->browse = "部门维护"; -$lang->dept->manage = "维护部门结构"; -$lang->dept->updateOrder = "更新排序"; -$lang->dept->users = "成员列表"; - -$lang->dept->saveButton = " 保存 (S) "; -$lang->dept->confirmDelete = " 您确定删除该部门吗?"; + + * @package dept + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->dept->common = '部门结构'; +$lang->dept->add = "添加"; +$lang->dept->addChild = "添加下级部门"; +$lang->dept->manageChild = "下级部门"; +$lang->dept->delete = "删除部门"; +$lang->dept->browse = "部门维护"; +$lang->dept->manage = "维护部门结构"; +$lang->dept->updateOrder = "更新排序"; +$lang->dept->users = "成员列表"; + +$lang->dept->saveButton = " 保存 (S) "; +$lang->dept->confirmDelete = " 您确定删除该部门吗?"; diff --git a/module/dept/lang/zh-tw.php b/module/dept/lang/zh-tw.php index 38c1e8959d..603a3dc22c 100644 --- a/module/dept/lang/zh-tw.php +++ b/module/dept/lang/zh-tw.php @@ -1,23 +1,23 @@ - - * @package dept - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->dept->common = '部門結構'; -$lang->dept->add = "添加"; -$lang->dept->addChild = "添加下級部門"; -$lang->dept->manageChild = "下級部門"; -$lang->dept->delete = "刪除部門"; -$lang->dept->browse = "部門維護"; -$lang->dept->manage = "維護部門結構"; -$lang->dept->updateOrder = "更新排序"; -$lang->dept->users = "成員列表"; - -$lang->dept->saveButton = " 保存 (S) "; -$lang->dept->confirmDelete = " 您確定刪除該部門嗎?"; + + * @package dept + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->dept->common = '部門結構'; +$lang->dept->add = "添加"; +$lang->dept->addChild = "添加下級部門"; +$lang->dept->manageChild = "下級部門"; +$lang->dept->delete = "刪除部門"; +$lang->dept->browse = "部門維護"; +$lang->dept->manage = "維護部門結構"; +$lang->dept->updateOrder = "更新排序"; +$lang->dept->users = "成員列表"; + +$lang->dept->saveButton = " 保存 (S) "; +$lang->dept->confirmDelete = " 您確定刪除該部門嗎?"; diff --git a/module/dept/model.php b/module/dept/model.php index 05a04945dc..f355eb8785 100644 --- a/module/dept/model.php +++ b/module/dept/model.php @@ -1,302 +1,302 @@ - - * @package dept - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->findById($deptID)->from(TABLE_DEPT)->fetch(); - } - - /** - * Build the query. - * - * @param int $rootDeptID - * @access public - * @return string - */ - public function buildMenuQuery($rootDeptID) - { - $rootDept = $this->getByID($rootDeptID); - if(!$rootDept) $rootDept->path = ''; - return $this->dao->select('*')->from(TABLE_DEPT) - ->beginIF($rootDeptID > 0)->where('path')->like($rootDept->path . '%')->fi() - ->orderBy('grade desc, `order`') - ->get(); - } - - /** - * Get option menu of departments. - * - * @param int $rootDeptID - * @access public - * @return array - */ - public function getOptionMenu($rootDeptID = 0) - { - $deptMenu = array(); - $stmt = $this->dbh->query($this->buildMenuQuery($rootDeptID)); - $depts = array(); - while($dept = $stmt->fetch()) $depts[$dept->id] = $dept; - - foreach($depts as $dept) - { - $parentDepts = explode(',', $dept->path); - $deptName = '/'; - foreach($parentDepts as $parentDeptID) - { - if(empty($parentDeptID)) continue; - $deptName .= $depts[$parentDeptID]->name . '/'; - } - $deptName = rtrim($deptName, '/'); - $deptName .= "|$dept->id\n"; - - if(isset($deptMenu[$dept->id]) and !empty($deptMenu[$dept->id])) - { - if(isset($deptMenu[$dept->parent])) - { - $deptMenu[$dept->parent] .= $deptName; - } - else - { - $deptMenu[$dept->parent] = $deptName;; - } - $deptMenu[$dept->parent] .= $deptMenu[$dept->id]; - } - else - { - if(isset($deptMenu[$dept->parent]) and !empty($deptMenu[$dept->parent])) - { - $deptMenu[$dept->parent] .= $deptName; - } - else - { - $deptMenu[$dept->parent] = $deptName; - } - } - } - - $topMenu = @array_pop($deptMenu); - $topMenu = explode("\n", trim($topMenu)); - $lastMenu[] = '/'; - foreach($topMenu as $menu) - { - if(!strpos($menu, '|')) continue; - list($label, $deptID) = explode('|', $menu); - $lastMenu[$deptID] = $label; - } - return $lastMenu; - } - - /** - * Get the treemenu of departments. - * - * @param int $rootDeptID - * @param string $userFunc - * @access public - * @return string - */ - public function getTreeMenu($rootDeptID = 0, $userFunc) - { - $deptMenu = array(); - $stmt = $this->dbh->query($this->buildMenuQuery($rootDeptID)); - while($dept = $stmt->fetch()) - { - $linkHtml = call_user_func($userFunc, $dept); - - if(isset($deptMenu[$dept->id]) and !empty($deptMenu[$dept->id])) - { - if(!isset($deptMenu[$dept->parent])) $deptMenu[$dept->parent] = ''; - $deptMenu[$dept->parent] .= "
    • $linkHtml"; - $deptMenu[$dept->parent] .= "
        ".$deptMenu[$dept->id]."
      \n"; - } - else - { - if(isset($deptMenu[$dept->parent]) and !empty($deptMenu[$dept->parent])) - { - $deptMenu[$dept->parent] .= "
    • $linkHtml\n"; - } - else - { - $deptMenu[$dept->parent] = "
    • $linkHtml\n"; - } - } - $deptMenu[$dept->parent] .= "
    • \n"; - } - - $lastMenu = "
        " . @array_pop($deptMenu) . "
      \n"; - return $lastMenu; - } - - /** - * Create the manage link. - * - * @param int $dept - * @access public - * @return string - */ - public function createManageLink($dept) - { - $linkHtml = $dept->name; - $linkHtml .= ' ' . html::a(helper::createLink('dept', 'browse', "deptid={$dept->id}"), $this->lang->dept->manageChild); - $linkHtml .= ' ' . html::a(helper::createLink('dept', 'delete', "deptid={$dept->id}"), $this->lang->dept->delete, 'hiddenwin'); - $linkHtml .= ' ' . html::input("orders[$dept->id]", $dept->order, 'style="width:30px;text-align:center"'); - return $linkHtml; - } - - /** - * Create the member link. - * - * @param int $dept - * @access public - * @return string - */ - public function createMemberLink($dept) - { - $linkHtml = html::a(helper::createLink('company', 'browse', "dept={$dept->id}"), $dept->name, '_self', "id='dept{$dept->id}'"); - return $linkHtml; - } - - /** - * Get sons of a department. - * - * @param int $deptID - * @access public - * @return array - */ - public function getSons($deptID) - { - return $this->dao->select('*')->from(TABLE_DEPT)->where('parent')->eq($deptID)->orderBy('`order`')->fetchAll(); - } - - /** - * Get all childs. - * - * @param int $deptID - * @access public - * @return array - */ - public function getAllChildId($deptID) - { - if($deptID == 0) return array(); - $dept = $this->getById($deptID); - $childs = $this->dao->select('id')->from(TABLE_DEPT)->where('path')->like($dept->path . '%')->fetchPairs(); - return array_keys($childs); - } - - /** - * Get parents. - * - * @param int $deptID - * @access public - * @return array - */ - public function getParents($deptID) - { - if($deptID == 0) return array(); - $path = $this->dao->select('path')->from(TABLE_DEPT)->where('id')->eq($deptID)->fetch('path'); - $path = substr($path, 1, -1); - if(empty($path)) return array(); - return $this->dao->select('*')->from(TABLE_DEPT)->where('id')->in($path)->orderBy('grade')->fetchAll(); - } - - /** - * Update order. - * - * @param int $orders - * @access public - * @return void - */ - public function updateOrder($orders) - { - foreach($orders as $deptID => $order) $this->dao->update(TABLE_DEPT)->set('`order`')->eq($order)->where('id')->eq($deptID)->exec(); - } - - /** - * Manage childs. - * - * @param int $parentDeptID - * @param string $childs - * @access public - * @return void - */ - public function manageChild($parentDeptID, $childs) - { - $parentDept = $this->getByID($parentDeptID); - if($parentDept) - { - $grade = $parentDept->grade + 1; - $parentPath = $parentDept->path; - } - else - { - $grade = 1; - $parentPath = ','; - } - - foreach($childs as $deptID => $deptName) - { - if(empty($deptName)) continue; - if(is_numeric($deptID)) - { - $dept->name = strip_tags($deptName); - $dept->parent = $parentDeptID; - $dept->grade = $grade; - $this->dao->insert(TABLE_DEPT)->data($dept)->exec(); - $deptID = $this->dao->lastInsertID(); - $childPath = $parentPath . "$deptID,"; - $this->dao->update(TABLE_DEPT)->set('path')->eq($childPath)->where('id')->eq($deptID)->exec(); - } - else - { - $deptID = str_replace('id', '', $deptID); - $this->dao->update(TABLE_DEPT)->set('name')->eq(strip_tags($deptName))->where('id')->eq($deptID)->exec(); - } - } - } - - /** - * Get users of a deparment. - * - * @param int $deptID - * @access public - * @return array - */ - public function getUsers($deptID) - { - return $this->dao->select('*')->from(TABLE_USER) - ->where('deleted')->eq(0) - ->beginIF($deptID)->andWhere('dept')->in($deptID)->fi() - ->orderBy('id') - ->fetchAll(); - } - - /** - * Delete a department. - * - * @param int $deptID - * @access public - * @return void - */ - public function delete($deptID) - { - $this->dao->delete()->from(TABLE_DEPT)->where('id')->eq($deptID)->exec(); - } -} + + * @package dept + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->findById($deptID)->from(TABLE_DEPT)->fetch(); + } + + /** + * Build the query. + * + * @param int $rootDeptID + * @access public + * @return string + */ + public function buildMenuQuery($rootDeptID) + { + $rootDept = $this->getByID($rootDeptID); + if(!$rootDept) $rootDept->path = ''; + return $this->dao->select('*')->from(TABLE_DEPT) + ->beginIF($rootDeptID > 0)->where('path')->like($rootDept->path . '%')->fi() + ->orderBy('grade desc, `order`') + ->get(); + } + + /** + * Get option menu of departments. + * + * @param int $rootDeptID + * @access public + * @return array + */ + public function getOptionMenu($rootDeptID = 0) + { + $deptMenu = array(); + $stmt = $this->dbh->query($this->buildMenuQuery($rootDeptID)); + $depts = array(); + while($dept = $stmt->fetch()) $depts[$dept->id] = $dept; + + foreach($depts as $dept) + { + $parentDepts = explode(',', $dept->path); + $deptName = '/'; + foreach($parentDepts as $parentDeptID) + { + if(empty($parentDeptID)) continue; + $deptName .= $depts[$parentDeptID]->name . '/'; + } + $deptName = rtrim($deptName, '/'); + $deptName .= "|$dept->id\n"; + + if(isset($deptMenu[$dept->id]) and !empty($deptMenu[$dept->id])) + { + if(isset($deptMenu[$dept->parent])) + { + $deptMenu[$dept->parent] .= $deptName; + } + else + { + $deptMenu[$dept->parent] = $deptName;; + } + $deptMenu[$dept->parent] .= $deptMenu[$dept->id]; + } + else + { + if(isset($deptMenu[$dept->parent]) and !empty($deptMenu[$dept->parent])) + { + $deptMenu[$dept->parent] .= $deptName; + } + else + { + $deptMenu[$dept->parent] = $deptName; + } + } + } + + $topMenu = @array_pop($deptMenu); + $topMenu = explode("\n", trim($topMenu)); + $lastMenu[] = '/'; + foreach($topMenu as $menu) + { + if(!strpos($menu, '|')) continue; + list($label, $deptID) = explode('|', $menu); + $lastMenu[$deptID] = $label; + } + return $lastMenu; + } + + /** + * Get the treemenu of departments. + * + * @param int $rootDeptID + * @param string $userFunc + * @access public + * @return string + */ + public function getTreeMenu($rootDeptID = 0, $userFunc) + { + $deptMenu = array(); + $stmt = $this->dbh->query($this->buildMenuQuery($rootDeptID)); + while($dept = $stmt->fetch()) + { + $linkHtml = call_user_func($userFunc, $dept); + + if(isset($deptMenu[$dept->id]) and !empty($deptMenu[$dept->id])) + { + if(!isset($deptMenu[$dept->parent])) $deptMenu[$dept->parent] = ''; + $deptMenu[$dept->parent] .= "
    • $linkHtml"; + $deptMenu[$dept->parent] .= "
        ".$deptMenu[$dept->id]."
      \n"; + } + else + { + if(isset($deptMenu[$dept->parent]) and !empty($deptMenu[$dept->parent])) + { + $deptMenu[$dept->parent] .= "
    • $linkHtml\n"; + } + else + { + $deptMenu[$dept->parent] = "
    • $linkHtml\n"; + } + } + $deptMenu[$dept->parent] .= "
    • \n"; + } + + $lastMenu = "
        " . @array_pop($deptMenu) . "
      \n"; + return $lastMenu; + } + + /** + * Create the manage link. + * + * @param int $dept + * @access public + * @return string + */ + public function createManageLink($dept) + { + $linkHtml = $dept->name; + $linkHtml .= ' ' . html::a(helper::createLink('dept', 'browse', "deptid={$dept->id}"), $this->lang->dept->manageChild); + $linkHtml .= ' ' . html::a(helper::createLink('dept', 'delete', "deptid={$dept->id}"), $this->lang->dept->delete, 'hiddenwin'); + $linkHtml .= ' ' . html::input("orders[$dept->id]", $dept->order, 'style="width:30px;text-align:center"'); + return $linkHtml; + } + + /** + * Create the member link. + * + * @param int $dept + * @access public + * @return string + */ + public function createMemberLink($dept) + { + $linkHtml = html::a(helper::createLink('company', 'browse', "dept={$dept->id}"), $dept->name, '_self', "id='dept{$dept->id}'"); + return $linkHtml; + } + + /** + * Get sons of a department. + * + * @param int $deptID + * @access public + * @return array + */ + public function getSons($deptID) + { + return $this->dao->select('*')->from(TABLE_DEPT)->where('parent')->eq($deptID)->orderBy('`order`')->fetchAll(); + } + + /** + * Get all childs. + * + * @param int $deptID + * @access public + * @return array + */ + public function getAllChildId($deptID) + { + if($deptID == 0) return array(); + $dept = $this->getById($deptID); + $childs = $this->dao->select('id')->from(TABLE_DEPT)->where('path')->like($dept->path . '%')->fetchPairs(); + return array_keys($childs); + } + + /** + * Get parents. + * + * @param int $deptID + * @access public + * @return array + */ + public function getParents($deptID) + { + if($deptID == 0) return array(); + $path = $this->dao->select('path')->from(TABLE_DEPT)->where('id')->eq($deptID)->fetch('path'); + $path = substr($path, 1, -1); + if(empty($path)) return array(); + return $this->dao->select('*')->from(TABLE_DEPT)->where('id')->in($path)->orderBy('grade')->fetchAll(); + } + + /** + * Update order. + * + * @param int $orders + * @access public + * @return void + */ + public function updateOrder($orders) + { + foreach($orders as $deptID => $order) $this->dao->update(TABLE_DEPT)->set('`order`')->eq($order)->where('id')->eq($deptID)->exec(); + } + + /** + * Manage childs. + * + * @param int $parentDeptID + * @param string $childs + * @access public + * @return void + */ + public function manageChild($parentDeptID, $childs) + { + $parentDept = $this->getByID($parentDeptID); + if($parentDept) + { + $grade = $parentDept->grade + 1; + $parentPath = $parentDept->path; + } + else + { + $grade = 1; + $parentPath = ','; + } + + foreach($childs as $deptID => $deptName) + { + if(empty($deptName)) continue; + if(is_numeric($deptID)) + { + $dept->name = strip_tags($deptName); + $dept->parent = $parentDeptID; + $dept->grade = $grade; + $this->dao->insert(TABLE_DEPT)->data($dept)->exec(); + $deptID = $this->dao->lastInsertID(); + $childPath = $parentPath . "$deptID,"; + $this->dao->update(TABLE_DEPT)->set('path')->eq($childPath)->where('id')->eq($deptID)->exec(); + } + else + { + $deptID = str_replace('id', '', $deptID); + $this->dao->update(TABLE_DEPT)->set('name')->eq(strip_tags($deptName))->where('id')->eq($deptID)->exec(); + } + } + } + + /** + * Get users of a deparment. + * + * @param int $deptID + * @access public + * @return array + */ + public function getUsers($deptID) + { + return $this->dao->select('*')->from(TABLE_USER) + ->where('deleted')->eq(0) + ->beginIF($deptID)->andWhere('dept')->in($deptID)->fi() + ->orderBy('id') + ->fetchAll(); + } + + /** + * Delete a department. + * + * @param int $deptID + * @access public + * @return void + */ + public function delete($deptID) + { + $this->dao->delete()->from(TABLE_DEPT)->where('id')->eq($deptID)->exec(); + } +} diff --git a/module/dept/view/browse.html.php b/module/dept/view/browse.html.php index debc7952cf..ad08d47328 100644 --- a/module/dept/view/browse.html.php +++ b/module/dept/view/browse.html.php @@ -1,67 +1,67 @@ - - * @package dept - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - -
      -
      '> - - - - - -
      title;?>
      -
      -
      dept->updateOrder);?>
      -
      -
      -
      -
      '> - - - - - - - - - -
      dept->manageChild;?>
      - - createLink('dept', 'browse'), $this->app->company->name); - echo $lang->arrow; - foreach($parentDepts as $dept) - { - echo html::a($this->createLink('dept', 'browse', "deptID=$dept->id"), $dept->name); - echo $lang->arrow; - } - ?> - - - id]", $sonDept->name) . '
      '; - for($i = 0; $i < DEPT::NEW_CHILD_COUNT ; $i ++) echo html::input("depts[]") . '
      '; - ?> -
      - - -
      -
      -
      - + + * @package dept + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + +
      +
      '> + + + + + +
      title;?>
      +
      +
      dept->updateOrder);?>
      +
      +
      +
      +
      '> + + + + + + + + + +
      dept->manageChild;?>
      + + createLink('dept', 'browse'), $this->app->company->name); + echo $lang->arrow; + foreach($parentDepts as $dept) + { + echo html::a($this->createLink('dept', 'browse', "deptID=$dept->id"), $dept->name); + echo $lang->arrow; + } + ?> + + + id]", $sonDept->name) . '
      '; + for($i = 0; $i < DEPT::NEW_CHILD_COUNT ; $i ++) echo html::input("depts[]") . '
      '; + ?> +
      + + +
      +
      +
      + diff --git a/module/doc/control.php b/module/doc/control.php index 11a4a85fb2..6aec9fb045 100644 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -1,420 +1,420 @@ - - * @package doc - * @version $Id: control.php 933 2010-07-06 06:53:40Z wwccss $ - * @link http://www.zentao.net - */ -class doc extends control -{ - /** - * Construct function, load user, tree, action auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('user'); - $this->loadModel('tree'); - $this->loadModel('action'); - $this->loadModel('product'); - $this->loadModel('project'); - $this->libs = $this->doc->getLibs(); - } - - /** - * Go to browse page. - * - * @access public - * @return void - */ - public function index() - { - $this->locate(inlink('browse')); - } - - /** - * Browse docs. - * - * @param string|int $libID product|project or the int id of custom library - * @param int $moduleID - * @param int $productID - * @param int $projectID - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function browse($libID = 'product', $moduleID = 0, $productID = 0, $projectID = 0, $browseType = 'byModule', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Set browseType.*/ - $browseType = strtolower($browseType); - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Set menu, save session. */ - $this->doc->setMenu($this->libs, $libID, 'doc'); - $this->session->set('docList', $this->app->getURI(true)); - - /* Set header and position. */ - $this->view->header->title = $this->lang->doc->index . $this->lang->colon . $this->libs[$libID]; - $this->view->position[] = $this->libs[$libID]; - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); - - /* Get docs. */ - $modules = 0; - $docs=array(); - if($browseType == "bymodule") - { - if($moduleID) $modules = $this->tree->getAllChildID($moduleID); - $docs = $this->doc->getDocs($libID, $productID, $projectID, $modules, $orderBy, $pager); - } - elseif($browseType == "bysearch") - { - if($queryID) - { - $query = $this->loadModel('search')->getQuery($queryID); - if($query) - { - $this->session->set('docQuery', $query->sql); - $this->session->set('docForm', $query->form); - } - else - { - $this->session->set('docQuery', ' 1 = 1'); - } - } - else - { - if($this->session->docQuery == false) $this->session->set('docQuery', ' 1 = 1'); - } - $docQuery = str_replace("`product` = 'all'", '1', $this->session->docQuery); // Search all producti. - $docQuery = str_replace("`project` = 'all'", '1', $docQuery); // Search all project. - $docs = $this->dao->select('*')->from(TABLE_DOC)->where($docQuery) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /* Get the tree menu. */ - if($libID == 'product') - { - $moduleTree = $this->tree->getProductDocTreeMenu(); - } - elseif($libID == 'project') - { - $moduleTree = $this->tree->getProjectDocTreeMenu(); - } - else - { - $moduleTree = $this->tree->getTreeMenu($libID, $viewType = 'customdoc', $startModuleID = 0, array('treeModel', 'createDocLink')); - } - - /* Build the search form. */ - $this->config->doc->search['actionURL'] = $this->createLink('doc', 'browse', "libID=$libID&moduleID=$moduleID&procuctID=$productID&projectID=$projectID&browseType=bySearch&queryID=myQueryID"); - $this->config->doc->search['queryID'] = $queryID; - $this->config->doc->search['params']['product']['values'] = array(''=>'') + $this->product->getPairs() + array('all'=>$this->lang->doc->allProduct); - $this->config->doc->search['params']['project']['values'] = array(''=>'') + $this->project->getPairs() + array('all'=>$this->lang->doc->allProject); - $this->config->doc->search['params']['lib']['values'] = array(''=>'') + $this->libs; - $this->config->doc->search['params']['type']['values'] = array(''=>'') + $this->config->doc->search['params']['type']['values']; - - /* Get the modules. */ - if($libID == 'product' or $libID == 'project') - { - $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); - } - else - { - $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); - } - $this->config->doc->search['params']['module']['values'] = array(''=>'') + $moduleOptionMenu; - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->doc->search); - - $this->view->libID = $libID; - $this->view->libName = $this->libs[$libID]; - $this->view->moduleID = $moduleID; - $this->view->moduleTree = $moduleTree; - $this->view->parentModules = $this->tree->getParents($moduleID); - $this->view->docs = $docs; - $this->view->pager = $pager; - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->orderBy = $orderBy; - $this->view->productID = $productID; - $this->view->projectID = $projectID; - $this->view->browseType = $browseType; - $this->view->param = $param; - - $this->display(); - } - - /** - * Create a library. - * - * @access public - * @return void - */ - public function createLib() - { - if(!empty($_POST)) - { - $libID = $this->doc->createLib(); - if(!dao::isError()) - { - $this->loadModel('action')->create('docLib', $libID, 'Created'); - die(js::locate($this->createLink($this->moduleName, 'browse', "libID=$libID"), 'parent')); - } - else - { - echo js::error(dao::getError()); - } - } - die($this->display()); - } - - /** - * Edit a library. - * - * @param int $libID - * @access public - * @return void - */ - public function editLib($libID) - { - if(!empty($_POST)) - { - $changes = $this->doc->updateLib($libID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('docLib', $libID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate($this->createLink($this->moduleName, 'browse', "libID=$libID"), 'parent')); - } - - $lib = $this->doc->getLibByID($libID); - $this->view->libName = empty($lib) ? $libID : $lib->name; - $this->view->libID = $libID; - - die($this->display()); - } - - /** - * Delete a library. - * - * @param int $libID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function deleteLib($libID, $confirm = 'no') - { - if($libID == 'product' or $libID == 'project') die(); - if($confirm == 'no') - { - die(js::confirm($this->lang->doc->confirmDeleteLib, $this->createLink('doc', 'deleteLib', "libID=$libID&confirm=yes"))); - } - else - { - $this->doc->delete(TABLE_DOCLIB, $libID); - die(js::locate($this->createLink('doc', 'browse'), 'parent')); - } - } - - /** - * Create a doc. - * - * @param int|string $libID - * @param int $moduleID - * @param int $productID - * @param int $projectID - * @param string $from - * @access public - * @return void - */ - public function create($libID, $moduleID = 0, $productID = 0, $projectID = 0, $from = 'doc') - { - $projectID = (int)$projectID; - if(!empty($_POST)) - { - $docID = $this->doc->create(); - if(dao::isError()) die(js::error(dao::getError())); - $this->action->create('doc', $docID, 'Created'); - - if($from == 'product') $link = $this->createLink('product', 'doc', "productID={$this->post->product}"); - if($from == 'project') $link = $this->createLink('project', 'doc', "projectID={$this->post->project}"); - if($from == 'doc') - { - $productID = intval($this->post->product); - $projectID = intval($this->post->project); - $vars = "libID=$libID&moduleID={$this->post->module}&productID=$productID&projectID=$projectID"; - $link = $this->createLink('doc', 'browse', $vars); - } - die(js::locate($link, 'parent')); - } - - $this->loadModel('product'); - $this->loadModel('project'); - - /* According the from, set menus. */ - if($from == 'product') - { - $this->lang->doc->menu = $this->lang->product->menu; - $this->product->setMenu($this->product->getPairs(), $productID); - $this->lang->set('menugroup.doc', 'product'); - } - elseif($from == 'project') - { - $this->lang->doc->menu = $this->lang->project->menu; - $this->project->setMenu($this->project->getPairs('nocode'), $projectID); - $this->lang->set('menugroup.doc', 'project'); - } - else - { - $this->doc->setMenu($this->libs, $libID); - } - - /* Get the modules. */ - if($libID == 'product' or $libID == 'project') - { - $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); - } - else - { - $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); - } - - $this->view->header->title = $this->libs[$libID] . $this->lang->colon . $this->lang->doc->create; - $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$libID"), $this->libs[$libID]); - $this->view->position[] = $this->lang->doc->create; - - $this->view->libID = $libID; - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->view->moduleID = $moduleID; - $this->view->productID = $productID; - $this->view->projectID = $projectID; - $this->view->products = $projectID == 0 ? $this->product->getPairs() : $this->project->getProducts($projectID); - $this->view->projects = $this->loadModel('project')->getPairs('all'); - - $this->display(); - } - - /** - * Edit a doc. - * - * @param int $docID - * @access public - * @return void - */ - public function edit($docID) - { - if(!empty($_POST)) - { - $changes = $this->doc->update($docID); - if(dao::isError()) die(js::error(dao::getError())); - $files = $this->loadModel('file')->saveUpload('doc', $docID); - if($this->post->comment != '' or !empty($changes) or !empty($files)) - { - $action = !empty($changes) ? 'Edited' : 'Commented'; - $fileAction = ''; - if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; - $actionID = $this->action->create('doc', $docID, $action, $fileAction . $this->post->comment); - $this->action->logHistory($actionID, $changes); - } - die(js::locate($this->createLink('doc', 'view', "docID=$docID"), 'parent')); - } - - /* Get doc and set menu. */ - $doc = $this->doc->getById($docID); - $libID = $doc->lib; - $this->doc->setMenu($this->libs, $libID); - - /* Get modules. */ - if($libID == 'product' or $libID == 'project') - { - $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); - } - else - { - $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); - } - - $this->view->header->title = $this->libs[$libID] . $this->lang->colon . $this->lang->doc->create; - $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$libID"), $this->libs[$libID]); - $this->view->position[] = $this->lang->doc->edit; - - $this->view->doc = $doc; - $this->view->libID = $libID; - $this->view->users = $this->user->getPairs('noclosed,nodeleted'); - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->display(); - } - - /** - * View a doc. - * - * @param int $docID - * @access public - * @return void - */ - public function view($docID) - { - /* Get doc. */ - $doc = $this->doc->getById($docID); - if(!$doc) die(js::error($this->lang->notFound) . js::locate('back')); - if($doc->project != 0 and !$this->project->checkPriv($this->project->getById($doc->project))) - { - echo(js::alert($this->lang->error->accessDenied)); - die(js::locate('back')); - } - - /* Get library. */ - $lib = $doc->libName; - if($doc->lib == 'product') $lib = $doc->productName; - if($doc->lib == 'project') $lib = $doc->productName . $this->lang->arrow . $doc->projectName; - - /* Set menu. */ - $this->doc->setMenu($this->libs, $doc->lib); - - $this->view->header->title = $this->libs[$doc->lib] . $this->lang->colon . $this->lang->doc->view; - $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$doc->lib"), $this->libs[$doc->lib]); - $this->view->position[] = $this->lang->doc->view; - - $this->view->doc = $doc; - $this->view->lib = $lib; - $this->view->actions = $this->loadModel('action')->getList('doc', $docID); - $this->view->users = $this->user->getPairs('noclosed,nodeleted'); - - $this->display(); - } - - /** - * Delete a doc. - * - * @param int $docID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($docID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->doc->confirmDelete, inlink('delete', "docID=$docID&confirm=yes"))); - } - else - { - $this->doc->delete(TABLE_DOC, $docID); - die(js::locate($this->session->docList, 'parent')); - } - } -} + + * @package doc + * @version $Id: control.php 933 2010-07-06 06:53:40Z wwccss $ + * @link http://www.zentao.net + */ +class doc extends control +{ + /** + * Construct function, load user, tree, action auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('user'); + $this->loadModel('tree'); + $this->loadModel('action'); + $this->loadModel('product'); + $this->loadModel('project'); + $this->libs = $this->doc->getLibs(); + } + + /** + * Go to browse page. + * + * @access public + * @return void + */ + public function index() + { + $this->locate(inlink('browse')); + } + + /** + * Browse docs. + * + * @param string|int $libID product|project or the int id of custom library + * @param int $moduleID + * @param int $productID + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($libID = 'product', $moduleID = 0, $productID = 0, $projectID = 0, $browseType = 'byModule', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Set browseType.*/ + $browseType = strtolower($browseType); + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Set menu, save session. */ + $this->doc->setMenu($this->libs, $libID, 'doc'); + $this->session->set('docList', $this->app->getURI(true)); + + /* Set header and position. */ + $this->view->header->title = $this->lang->doc->index . $this->lang->colon . $this->libs[$libID]; + $this->view->position[] = $this->libs[$libID]; + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + /* Get docs. */ + $modules = 0; + $docs=array(); + if($browseType == "bymodule") + { + if($moduleID) $modules = $this->tree->getAllChildID($moduleID); + $docs = $this->doc->getDocs($libID, $productID, $projectID, $modules, $orderBy, $pager); + } + elseif($browseType == "bysearch") + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('docQuery', $query->sql); + $this->session->set('docForm', $query->form); + } + else + { + $this->session->set('docQuery', ' 1 = 1'); + } + } + else + { + if($this->session->docQuery == false) $this->session->set('docQuery', ' 1 = 1'); + } + $docQuery = str_replace("`product` = 'all'", '1', $this->session->docQuery); // Search all producti. + $docQuery = str_replace("`project` = 'all'", '1', $docQuery); // Search all project. + $docs = $this->dao->select('*')->from(TABLE_DOC)->where($docQuery) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* Get the tree menu. */ + if($libID == 'product') + { + $moduleTree = $this->tree->getProductDocTreeMenu(); + } + elseif($libID == 'project') + { + $moduleTree = $this->tree->getProjectDocTreeMenu(); + } + else + { + $moduleTree = $this->tree->getTreeMenu($libID, $viewType = 'customdoc', $startModuleID = 0, array('treeModel', 'createDocLink')); + } + + /* Build the search form. */ + $this->config->doc->search['actionURL'] = $this->createLink('doc', 'browse', "libID=$libID&moduleID=$moduleID&procuctID=$productID&projectID=$projectID&browseType=bySearch&queryID=myQueryID"); + $this->config->doc->search['queryID'] = $queryID; + $this->config->doc->search['params']['product']['values'] = array(''=>'') + $this->product->getPairs() + array('all'=>$this->lang->doc->allProduct); + $this->config->doc->search['params']['project']['values'] = array(''=>'') + $this->project->getPairs() + array('all'=>$this->lang->doc->allProject); + $this->config->doc->search['params']['lib']['values'] = array(''=>'') + $this->libs; + $this->config->doc->search['params']['type']['values'] = array(''=>'') + $this->config->doc->search['params']['type']['values']; + + /* Get the modules. */ + if($libID == 'product' or $libID == 'project') + { + $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); + } + else + { + $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); + } + $this->config->doc->search['params']['module']['values'] = array(''=>'') + $moduleOptionMenu; + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->doc->search); + + $this->view->libID = $libID; + $this->view->libName = $this->libs[$libID]; + $this->view->moduleID = $moduleID; + $this->view->moduleTree = $moduleTree; + $this->view->parentModules = $this->tree->getParents($moduleID); + $this->view->docs = $docs; + $this->view->pager = $pager; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->orderBy = $orderBy; + $this->view->productID = $productID; + $this->view->projectID = $projectID; + $this->view->browseType = $browseType; + $this->view->param = $param; + + $this->display(); + } + + /** + * Create a library. + * + * @access public + * @return void + */ + public function createLib() + { + if(!empty($_POST)) + { + $libID = $this->doc->createLib(); + if(!dao::isError()) + { + $this->loadModel('action')->create('docLib', $libID, 'Created'); + die(js::locate($this->createLink($this->moduleName, 'browse', "libID=$libID"), 'parent')); + } + else + { + echo js::error(dao::getError()); + } + } + die($this->display()); + } + + /** + * Edit a library. + * + * @param int $libID + * @access public + * @return void + */ + public function editLib($libID) + { + if(!empty($_POST)) + { + $changes = $this->doc->updateLib($libID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('docLib', $libID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate($this->createLink($this->moduleName, 'browse', "libID=$libID"), 'parent')); + } + + $lib = $this->doc->getLibByID($libID); + $this->view->libName = empty($lib) ? $libID : $lib->name; + $this->view->libID = $libID; + + die($this->display()); + } + + /** + * Delete a library. + * + * @param int $libID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function deleteLib($libID, $confirm = 'no') + { + if($libID == 'product' or $libID == 'project') die(); + if($confirm == 'no') + { + die(js::confirm($this->lang->doc->confirmDeleteLib, $this->createLink('doc', 'deleteLib', "libID=$libID&confirm=yes"))); + } + else + { + $this->doc->delete(TABLE_DOCLIB, $libID); + die(js::locate($this->createLink('doc', 'browse'), 'parent')); + } + } + + /** + * Create a doc. + * + * @param int|string $libID + * @param int $moduleID + * @param int $productID + * @param int $projectID + * @param string $from + * @access public + * @return void + */ + public function create($libID, $moduleID = 0, $productID = 0, $projectID = 0, $from = 'doc') + { + $projectID = (int)$projectID; + if(!empty($_POST)) + { + $docID = $this->doc->create(); + if(dao::isError()) die(js::error(dao::getError())); + $this->action->create('doc', $docID, 'Created'); + + if($from == 'product') $link = $this->createLink('product', 'doc', "productID={$this->post->product}"); + if($from == 'project') $link = $this->createLink('project', 'doc', "projectID={$this->post->project}"); + if($from == 'doc') + { + $productID = intval($this->post->product); + $projectID = intval($this->post->project); + $vars = "libID=$libID&moduleID={$this->post->module}&productID=$productID&projectID=$projectID"; + $link = $this->createLink('doc', 'browse', $vars); + } + die(js::locate($link, 'parent')); + } + + $this->loadModel('product'); + $this->loadModel('project'); + + /* According the from, set menus. */ + if($from == 'product') + { + $this->lang->doc->menu = $this->lang->product->menu; + $this->product->setMenu($this->product->getPairs(), $productID); + $this->lang->set('menugroup.doc', 'product'); + } + elseif($from == 'project') + { + $this->lang->doc->menu = $this->lang->project->menu; + $this->project->setMenu($this->project->getPairs('nocode'), $projectID); + $this->lang->set('menugroup.doc', 'project'); + } + else + { + $this->doc->setMenu($this->libs, $libID); + } + + /* Get the modules. */ + if($libID == 'product' or $libID == 'project') + { + $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); + } + else + { + $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); + } + + $this->view->header->title = $this->libs[$libID] . $this->lang->colon . $this->lang->doc->create; + $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$libID"), $this->libs[$libID]); + $this->view->position[] = $this->lang->doc->create; + + $this->view->libID = $libID; + $this->view->moduleOptionMenu = $moduleOptionMenu; + $this->view->moduleID = $moduleID; + $this->view->productID = $productID; + $this->view->projectID = $projectID; + $this->view->products = $projectID == 0 ? $this->product->getPairs() : $this->project->getProducts($projectID); + $this->view->projects = $this->loadModel('project')->getPairs('all'); + + $this->display(); + } + + /** + * Edit a doc. + * + * @param int $docID + * @access public + * @return void + */ + public function edit($docID) + { + if(!empty($_POST)) + { + $changes = $this->doc->update($docID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('doc', $docID); + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $action = !empty($changes) ? 'Edited' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; + $actionID = $this->action->create('doc', $docID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + } + die(js::locate($this->createLink('doc', 'view', "docID=$docID"), 'parent')); + } + + /* Get doc and set menu. */ + $doc = $this->doc->getById($docID); + $libID = $doc->lib; + $this->doc->setMenu($this->libs, $libID); + + /* Get modules. */ + if($libID == 'product' or $libID == 'project') + { + $moduleOptionMenu = $this->tree->getOptionMenu(0, $libID . 'doc', $startModuleID = 0); + } + else + { + $moduleOptionMenu = $this->tree->getOptionMenu($libID, 'customdoc', $startModuleID = 0); + } + + $this->view->header->title = $this->libs[$libID] . $this->lang->colon . $this->lang->doc->create; + $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$libID"), $this->libs[$libID]); + $this->view->position[] = $this->lang->doc->edit; + + $this->view->doc = $doc; + $this->view->libID = $libID; + $this->view->users = $this->user->getPairs('noclosed,nodeleted'); + $this->view->moduleOptionMenu = $moduleOptionMenu; + $this->display(); + } + + /** + * View a doc. + * + * @param int $docID + * @access public + * @return void + */ + public function view($docID) + { + /* Get doc. */ + $doc = $this->doc->getById($docID); + if(!$doc) die(js::error($this->lang->notFound) . js::locate('back')); + if($doc->project != 0 and !$this->project->checkPriv($this->project->getById($doc->project))) + { + echo(js::alert($this->lang->error->accessDenied)); + die(js::locate('back')); + } + + /* Get library. */ + $lib = $doc->libName; + if($doc->lib == 'product') $lib = $doc->productName; + if($doc->lib == 'project') $lib = $doc->productName . $this->lang->arrow . $doc->projectName; + + /* Set menu. */ + $this->doc->setMenu($this->libs, $doc->lib); + + $this->view->header->title = $this->libs[$doc->lib] . $this->lang->colon . $this->lang->doc->view; + $this->view->position[] = html::a($this->createLink('doc', 'browse', "libID=$doc->lib"), $this->libs[$doc->lib]); + $this->view->position[] = $this->lang->doc->view; + + $this->view->doc = $doc; + $this->view->lib = $lib; + $this->view->actions = $this->loadModel('action')->getList('doc', $docID); + $this->view->users = $this->user->getPairs('noclosed,nodeleted'); + + $this->display(); + } + + /** + * Delete a doc. + * + * @param int $docID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($docID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->doc->confirmDelete, inlink('delete', "docID=$docID&confirm=yes"))); + } + else + { + $this->doc->delete(TABLE_DOC, $docID); + die(js::locate($this->session->docList, 'parent')); + } + } +} diff --git a/module/doc/lang/en.php b/module/doc/lang/en.php index 2df0055ddb..44ffcc972e 100644 --- a/module/doc/lang/en.php +++ b/module/doc/lang/en.php @@ -1,65 +1,65 @@ - - * @package doc - * @version $Id: en.php 824 2010-05-02 15:32:06Z wwccss $ - * @link http://www.zentao.net - */ -/* Fields. */ -$lang->doc->common = 'Doc'; -$lang->doc->id = 'ID'; -$lang->doc->product = 'Product'; -$lang->doc->project = 'Project'; -$lang->doc->lib = 'Library'; -$lang->doc->module = 'Module'; -$lang->doc->title = 'Title'; -$lang->doc->digest = 'Digest'; -$lang->doc->comment = 'Comment'; -$lang->doc->type = 'Type'; -$lang->doc->content = 'Content'; -$lang->doc->keywords = 'Keywords'; -$lang->doc->url = 'URL'; -$lang->doc->files = 'File'; -$lang->doc->views = 'Views'; -$lang->doc->addedBy = 'Added by'; -$lang->doc->addedDate = 'Added date'; -$lang->doc->editedBy = 'Edited by'; -$lang->doc->editedDate = 'Edited date'; - -$lang->doc->moduleDoc = 'By module'; -$lang->doc->searchDoc = 'By search'; -//$lang->doc->allDoc = 'All document'; - -$lang->doc->moduleName = 'Module name'; -$lang->doc->moduleOrder = 'Module order'; - -/* Actions. */ -$lang->doc->index = 'Index'; -$lang->doc->create = 'Create doc'; -$lang->doc->edit = 'Edit doc'; -$lang->doc->delete = 'Delete doc'; -$lang->doc->browse = 'Browse doc'; -$lang->doc->view = 'View doc'; -$lang->doc->createLib = 'Create library'; -$lang->doc->editLib = 'Edit library'; -$lang->doc->deleteLib = 'Delete library'; -$lang->doc->libName = 'Library name'; - -/* Browse tabs. */ -$lang->doc->allProduct = 'All products'; -$lang->doc->allProject = 'All projects'; - -$lang->doc->systemLibs['product'] = 'Product doc'; -$lang->doc->systemLibs['project'] = 'Project doc'; - -$lang->doc->types['file'] = 'File'; -$lang->doc->types['url'] = 'Link'; -$lang->doc->types['text'] = 'Html'; - -$lang->doc->confirmDelete = "Are you sure to delete this doc?"; -$lang->doc->confirmDeleteLib = " Are you sure to delete this doc library?"; -$lang->doc->errorEditSystemDoc = "System doc library needn't edit"; + + * @package doc + * @version $Id: en.php 824 2010-05-02 15:32:06Z wwccss $ + * @link http://www.zentao.net + */ +/* Fields. */ +$lang->doc->common = 'Doc'; +$lang->doc->id = 'ID'; +$lang->doc->product = 'Product'; +$lang->doc->project = 'Project'; +$lang->doc->lib = 'Library'; +$lang->doc->module = 'Module'; +$lang->doc->title = 'Title'; +$lang->doc->digest = 'Digest'; +$lang->doc->comment = 'Comment'; +$lang->doc->type = 'Type'; +$lang->doc->content = 'Content'; +$lang->doc->keywords = 'Keywords'; +$lang->doc->url = 'URL'; +$lang->doc->files = 'File'; +$lang->doc->views = 'Views'; +$lang->doc->addedBy = 'Added by'; +$lang->doc->addedDate = 'Added date'; +$lang->doc->editedBy = 'Edited by'; +$lang->doc->editedDate = 'Edited date'; + +$lang->doc->moduleDoc = 'By module'; +$lang->doc->searchDoc = 'By search'; +//$lang->doc->allDoc = 'All document'; + +$lang->doc->moduleName = 'Module name'; +$lang->doc->moduleOrder = 'Module order'; + +/* Actions. */ +$lang->doc->index = 'Index'; +$lang->doc->create = 'Create doc'; +$lang->doc->edit = 'Edit doc'; +$lang->doc->delete = 'Delete doc'; +$lang->doc->browse = 'Browse doc'; +$lang->doc->view = 'View doc'; +$lang->doc->createLib = 'Create library'; +$lang->doc->editLib = 'Edit library'; +$lang->doc->deleteLib = 'Delete library'; +$lang->doc->libName = 'Library name'; + +/* Browse tabs. */ +$lang->doc->allProduct = 'All products'; +$lang->doc->allProject = 'All projects'; + +$lang->doc->systemLibs['product'] = 'Product doc'; +$lang->doc->systemLibs['project'] = 'Project doc'; + +$lang->doc->types['file'] = 'File'; +$lang->doc->types['url'] = 'Link'; +$lang->doc->types['text'] = 'Html'; + +$lang->doc->confirmDelete = "Are you sure to delete this doc?"; +$lang->doc->confirmDeleteLib = " Are you sure to delete this doc library?"; +$lang->doc->errorEditSystemDoc = "System doc library needn't edit"; diff --git a/module/doc/lang/zh-cn.php b/module/doc/lang/zh-cn.php index b980621798..83a597e482 100644 --- a/module/doc/lang/zh-cn.php +++ b/module/doc/lang/zh-cn.php @@ -1,65 +1,65 @@ - - * @package doc - * @version $Id: zh-cn.php 824 2010-05-02 15:32:06Z wwccss $ - * @link http://www.zentao.net - */ -/* 字段列表。*/ -$lang->doc->common = '文档视图'; -$lang->doc->id = '文档编号'; -$lang->doc->product = '所属产品'; -$lang->doc->project = '所属项目'; -$lang->doc->lib = '所属文档库'; -$lang->doc->module = '所属分类'; -$lang->doc->title = '文档标题'; -$lang->doc->digest = '文档摘要'; -$lang->doc->comment = '文档备注'; -$lang->doc->type = '文档类型'; -$lang->doc->content = '文档正文'; -$lang->doc->keywords = '关键字'; -$lang->doc->url = '文档URL'; -$lang->doc->files = '附件'; -$lang->doc->views = '查阅次数'; -$lang->doc->addedBy = '由谁添加'; -$lang->doc->addedDate = '添加时间'; -$lang->doc->editedBy = '由谁编辑'; -$lang->doc->editedDate = '编辑时间'; - -$lang->doc->moduleDoc = '按模块浏览'; -$lang->doc->searchDoc = '搜索'; -//$lang->doc->allDoc = '所有文档'; - -$lang->doc->moduleName = '模块名称'; -$lang->doc->moduleOrder = '模块排序'; - -/* 方法列表。*/ -$lang->doc->index = '首页'; -$lang->doc->create = '创建文档'; -$lang->doc->edit = '编辑文档'; -$lang->doc->delete = '删除文档'; -$lang->doc->browse = '文档列表'; -$lang->doc->view = '文档详情'; -$lang->doc->createLib = '创建文档库'; -$lang->doc->editLib = '编辑文档库'; -$lang->doc->deleteLib = '删除文档库'; -$lang->doc->libName = '文档库名称'; - -/* 查询条件列表 */ -$lang->doc->allProduct = '所有产品'; -$lang->doc->allProject = '所有项目'; - -$lang->doc->systemLibs['product'] = '产品文档库'; -$lang->doc->systemLibs['project'] = '项目文档库'; - -$lang->doc->types['file'] = '文件'; -$lang->doc->types['url'] = '链接'; -$lang->doc->types['text'] = '网页'; - -$lang->doc->confirmDelete = "您确定删除该文档吗?"; -$lang->doc->confirmDeleteLib = " 您确定删除该文档库吗?"; -$lang->doc->errorEditSystemDoc = "系统文档库无需修改。"; + + * @package doc + * @version $Id: zh-cn.php 824 2010-05-02 15:32:06Z wwccss $ + * @link http://www.zentao.net + */ +/* 字段列表。*/ +$lang->doc->common = '文档视图'; +$lang->doc->id = '文档编号'; +$lang->doc->product = '所属产品'; +$lang->doc->project = '所属项目'; +$lang->doc->lib = '所属文档库'; +$lang->doc->module = '所属分类'; +$lang->doc->title = '文档标题'; +$lang->doc->digest = '文档摘要'; +$lang->doc->comment = '文档备注'; +$lang->doc->type = '文档类型'; +$lang->doc->content = '文档正文'; +$lang->doc->keywords = '关键字'; +$lang->doc->url = '文档URL'; +$lang->doc->files = '附件'; +$lang->doc->views = '查阅次数'; +$lang->doc->addedBy = '由谁添加'; +$lang->doc->addedDate = '添加时间'; +$lang->doc->editedBy = '由谁编辑'; +$lang->doc->editedDate = '编辑时间'; + +$lang->doc->moduleDoc = '按模块浏览'; +$lang->doc->searchDoc = '搜索'; +//$lang->doc->allDoc = '所有文档'; + +$lang->doc->moduleName = '模块名称'; +$lang->doc->moduleOrder = '模块排序'; + +/* 方法列表。*/ +$lang->doc->index = '首页'; +$lang->doc->create = '创建文档'; +$lang->doc->edit = '编辑文档'; +$lang->doc->delete = '删除文档'; +$lang->doc->browse = '文档列表'; +$lang->doc->view = '文档详情'; +$lang->doc->createLib = '创建文档库'; +$lang->doc->editLib = '编辑文档库'; +$lang->doc->deleteLib = '删除文档库'; +$lang->doc->libName = '文档库名称'; + +/* 查询条件列表 */ +$lang->doc->allProduct = '所有产品'; +$lang->doc->allProject = '所有项目'; + +$lang->doc->systemLibs['product'] = '产品文档库'; +$lang->doc->systemLibs['project'] = '项目文档库'; + +$lang->doc->types['file'] = '文件'; +$lang->doc->types['url'] = '链接'; +$lang->doc->types['text'] = '网页'; + +$lang->doc->confirmDelete = "您确定删除该文档吗?"; +$lang->doc->confirmDeleteLib = " 您确定删除该文档库吗?"; +$lang->doc->errorEditSystemDoc = "系统文档库无需修改。"; diff --git a/module/doc/lang/zh-tw.php b/module/doc/lang/zh-tw.php index 28aaee6e43..b9a69524af 100644 --- a/module/doc/lang/zh-tw.php +++ b/module/doc/lang/zh-tw.php @@ -1,65 +1,65 @@ - - * @package doc - * @version $Id: zh-tw.php 824 2010-05-02 15:32:06Z wwccss $ - * @link http://www.zentao.net - */ -/* 欄位列表。*/ -$lang->doc->common = '文檔視圖'; -$lang->doc->id = '文檔編號'; -$lang->doc->product = '所屬產品'; -$lang->doc->project = '所屬項目'; -$lang->doc->lib = '所屬文檔庫'; -$lang->doc->module = '所屬分類'; -$lang->doc->title = '文檔標題'; -$lang->doc->digest = '文檔摘要'; -$lang->doc->comment = '文檔備註'; -$lang->doc->type = '文檔類型'; -$lang->doc->content = '文檔正文'; -$lang->doc->keywords = '關鍵字'; -$lang->doc->url = '文檔URL'; -$lang->doc->files = '附件'; -$lang->doc->views = '查閲次數'; -$lang->doc->addedBy = '由誰添加'; -$lang->doc->addedDate = '添加時間'; -$lang->doc->editedBy = '由誰編輯'; -$lang->doc->editedDate = '編輯時間'; - -$lang->doc->moduleDoc = '按模組瀏覽'; -$lang->doc->searchDoc = '搜索'; -//$lang->doc->allDoc = '所有文檔'; - -$lang->doc->moduleName = '模組名稱'; -$lang->doc->moduleOrder = '模組排序'; - -/* 方法列表。*/ -$lang->doc->index = '首頁'; -$lang->doc->create = '創建文檔'; -$lang->doc->edit = '編輯文檔'; -$lang->doc->delete = '刪除文檔'; -$lang->doc->browse = '文檔列表'; -$lang->doc->view = '文檔詳情'; -$lang->doc->createLib = '創建文檔庫'; -$lang->doc->editLib = '編輯文檔庫'; -$lang->doc->deleteLib = '刪除文檔庫'; -$lang->doc->libName = '文檔庫名稱'; - -/* 查詢條件列表 */ -$lang->doc->allProduct = '所有產品'; -$lang->doc->allProject = '所有項目'; - -$lang->doc->systemLibs['product'] = '產品文檔庫'; -$lang->doc->systemLibs['project'] = '項目文檔庫'; - -$lang->doc->types['file'] = '檔案'; -$lang->doc->types['url'] = '連結'; -$lang->doc->types['text'] = '網頁'; - -$lang->doc->confirmDelete = "您確定刪除該文檔嗎?"; -$lang->doc->confirmDeleteLib = " 您確定刪除該文檔庫嗎?"; -$lang->doc->errorEditSystemDoc = "系統文檔庫無需修改。"; + + * @package doc + * @version $Id: zh-tw.php 824 2010-05-02 15:32:06Z wwccss $ + * @link http://www.zentao.net + */ +/* 欄位列表。*/ +$lang->doc->common = '文檔視圖'; +$lang->doc->id = '文檔編號'; +$lang->doc->product = '所屬產品'; +$lang->doc->project = '所屬項目'; +$lang->doc->lib = '所屬文檔庫'; +$lang->doc->module = '所屬分類'; +$lang->doc->title = '文檔標題'; +$lang->doc->digest = '文檔摘要'; +$lang->doc->comment = '文檔備註'; +$lang->doc->type = '文檔類型'; +$lang->doc->content = '文檔正文'; +$lang->doc->keywords = '關鍵字'; +$lang->doc->url = '文檔URL'; +$lang->doc->files = '附件'; +$lang->doc->views = '查閲次數'; +$lang->doc->addedBy = '由誰添加'; +$lang->doc->addedDate = '添加時間'; +$lang->doc->editedBy = '由誰編輯'; +$lang->doc->editedDate = '編輯時間'; + +$lang->doc->moduleDoc = '按模組瀏覽'; +$lang->doc->searchDoc = '搜索'; +//$lang->doc->allDoc = '所有文檔'; + +$lang->doc->moduleName = '模組名稱'; +$lang->doc->moduleOrder = '模組排序'; + +/* 方法列表。*/ +$lang->doc->index = '首頁'; +$lang->doc->create = '創建文檔'; +$lang->doc->edit = '編輯文檔'; +$lang->doc->delete = '刪除文檔'; +$lang->doc->browse = '文檔列表'; +$lang->doc->view = '文檔詳情'; +$lang->doc->createLib = '創建文檔庫'; +$lang->doc->editLib = '編輯文檔庫'; +$lang->doc->deleteLib = '刪除文檔庫'; +$lang->doc->libName = '文檔庫名稱'; + +/* 查詢條件列表 */ +$lang->doc->allProduct = '所有產品'; +$lang->doc->allProject = '所有項目'; + +$lang->doc->systemLibs['product'] = '產品文檔庫'; +$lang->doc->systemLibs['project'] = '項目文檔庫'; + +$lang->doc->types['file'] = '檔案'; +$lang->doc->types['url'] = '連結'; +$lang->doc->types['text'] = '網頁'; + +$lang->doc->confirmDelete = "您確定刪除該文檔嗎?"; +$lang->doc->confirmDeleteLib = " 您確定刪除該文檔庫嗎?"; +$lang->doc->errorEditSystemDoc = "系統文檔庫無需修改。"; diff --git a/module/doc/model.php b/module/doc/model.php index b7befc86ae..ab944be65c 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -1,281 +1,281 @@ - - * @package doc - * @version $Id: model.php 881 2010-06-22 06:50:32Z chencongzhi520 $ - * @link http://www.zentao.net - */ -?> -app->getModuleName(); - $currentMethod = $this->app->getMethodName(); - - $selectHtml = html::select('libID', $libs, $libID, "onchange=\"switchDocLib(this.value, '$currentModule', '$currentMethod', '$extra');\""); - common::setMenuVars($this->lang->doc->menu, 'list', $selectHtml . $this->lang->arrow); - foreach($this->lang->doc->menu as $key => $menu) - { - if($key != 'list') common::setMenuVars($this->lang->doc->menu, $key, $libID); - } - } - - /** - * Get library by id. - * - * @param int $libID - * @access public - * @return object - */ - public function getLibById($libID) - { - return $this->dao->findByID($libID)->from(TABLE_DOCLIB)->fetch(); - } - - /** - * Get libraries. - * - * @access public - * @return array - */ - public function getLibs() - { - $libs = $this->dao->select('id, name')->from(TABLE_DOCLIB)->where('deleted')->eq(0)->fetchPairs(); - return $this->lang->doc->systemLibs + $libs; - } - - /** - * Create a library. - * - * @access public - * @return void - */ - public function createLib() - { - $lib = fixer::input('post')->stripTags('name')->get(); - $this->dao->insert(TABLE_DOCLIB) - ->data($lib) - ->autoCheck() - ->batchCheck('name', 'notempty') - ->check('name', 'unique') - ->exec(); - return $this->dao->lastInsertID(); - } - - /** - * Update a library. - * - * @param int $libID - * @access public - * @return void - */ - public function updateLib($libID) - { - $libID = (int)$libID; - $oldLib = $this->getLibById($libID); - $lib = fixer::input('post')->stripTags('name')->get(); - $this->dao->update(TABLE_DOCLIB) - ->data($lib) - ->autoCheck() - ->batchCheck('name', 'notempty') - ->check('name', 'unique', "id != $libID") - ->where('id')->eq($libID) - ->exec(); - if(!dao::isError()) return common::createChanges($oldLib, $lib); - } - - /** - * Get docs. - * - * @param int|string $libID - * @param int $productID - * @param int $projectID - * @param int $module - * @param string $orderBy - * @param object $pager - * @access public - * @return void - */ - public function getDocs($libID, $productID, $projectID, $module, $orderBy, $pager) - { - $products = $this->loadModel('product')->getPairs(); - $projects = $this->loadModel('project')->getPairs(); - $keysOfProducts = array_keys($products); - $keysOfProjects = array_keys($projects); - $allKeysOfProjects = $keysOfProjects; - $allKeysOfProjects[] = 0; - - return $this->dao->select('*')->from(TABLE_DOC) - ->where('deleted')->eq(0) - ->beginIF(is_numeric($libID))->andWhere('lib')->eq($libID)->fi() - ->beginIF($libID == 'product')->andWhere('product')->in($keysOfProducts)->andWhere('project')->in($allKeysOfProjects)->fi() - ->beginIF($libID == 'project')->andWhere('project')->in($keysOfProjects)->fi() - ->beginIF($productID > 0)->andWhere('product')->eq($productID)->fi() - ->beginIF($projectID > 0)->andWhere('project')->eq($projectID)->fi() - ->beginIF((string)$projectID == 'int')->andWhere('project')->gt(0)->fi() - ->beginIF($module)->andWhere('module')->in($module)->fi() - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - } - - /** - * Get doc info by id. - * - * @param int $docID - * @access public - * @return void - */ - public function getById($docID) - { - $doc = $this->dao->select('*') - ->from(TABLE_DOC) - ->where('id')->eq((int)$docID) - ->fetch(); - if(!$doc) return false; - $doc->content = $this->loadModel('file')->setImgSize($doc->content); - $doc->files = $this->loadModel('file')->getByObject('doc', $docID); - - $doc->libName = ''; - $doc->productName = ''; - $doc->projectName = ''; - $doc->moduleName = ''; - if($doc->lib) $doc->libName = $this->dao->findByID($doc->lib)->from(TABLE_DOCLIB)->fetch('name'); - if($doc->product) $doc->productName = $this->dao->findByID($doc->product)->from(TABLE_PRODUCT)->fetch('name'); - if($doc->project) $doc->projectName = $this->dao->findByID($doc->project)->from(TABLE_PROJECT)->fetch('name'); - if($doc->module) $doc->moduleName = $this->dao->findByID($doc->module)->from(TABLE_MODULE)->fetch('name'); - return $doc; - } - - /** - * Create a doc. - * - * @access public - * @return void - */ - public function create() - { - $now = helper::now(); - $doc = fixer::input('post') - ->add('addedBy', $this->app->user->account) - ->add('addedDate', $now) - ->setDefault('product, project, module', 0) - ->specialChars('title, digest, keywords') - ->encodeURL('url') - ->cleanInt('product, project, module') - ->remove('files, labels') - ->get(); - $condition = "lib = '$doc->lib' AND module = $doc->module"; - $this->dao->insert(TABLE_DOC) - ->data($doc) - ->autoCheck() - ->batchCheck($this->config->doc->create->requiredFields, 'notempty') - ->check('title', 'unique', $condition) - ->exec(); - if(!dao::isError()) - { - $docID = $this->dao->lastInsertID(); - $this->loadModel('file')->saveUpload('doc', $docID); - return $docID; - } - return false; - } - - /** - * Update a doc. - * - * @param int $docID - * @access public - * @return void - */ - public function update($docID) - { - $oldDoc = $this->getById($docID); - $now = helper::now(); - $doc = fixer::input('post') - ->cleanInt('module') - ->setDefault('module', 0) - ->specialChars('title, digest, keywords') - ->encodeURL('url') - ->remove('comment,files, labels') - ->add('editedBy', $this->app->user->account) - ->add('editedDate', $now) - ->get(); - - $condition = "lib = '$doc->lib' AND module = $doc->module AND id != $docID"; - $this->dao->update(TABLE_DOC)->data($doc) - ->autoCheck() - ->batchCheck($this->config->doc->edit->requiredFields, 'notempty') - ->check('title', 'unique', $condition) - ->where('id')->eq((int)$docID) - ->exec(); - if(!dao::isError()) return common::createChanges($oldDoc, $doc); - } - - /** - * Get docs of a product. - * - * @param int $productID - * @access public - * @return array - */ - public function getProductDocs($productID) - { - return $this->dao->select('t1.*, t2.name as module') - ->from(TABLE_DOC)->alias('t1') - ->leftjoin(TABLE_MODULE)->alias('t2')->on('t1.module = t2.id') - ->where('t1.product')->eq($productID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy('t1.id_desc') - ->fetchAll(); - } - - /** - * Get docs of a project. - * - * @param int $projectID - * @access public - * @return array - */ - public function getProjectDocs($projectID) - { - return $this->dao->findByProject($projectID)->from(TABLE_DOC)->andWhere('deleted')->eq(0)->orderBy('id_desc')->fetchAll(); - } - - /** - * Get pairs of product modules. - * - * @access public - * @return array - */ - public function getProductModulePairs() - { - return $this->dao->findByType('productdoc')->from(TABLE_MODULE)->fetchPairs('id', 'name'); - } - - /** - * Get pairs of project modules. - * - * @access public - * @return array - */ - public function getProjectModulePairs() - { - return $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->andWhere('type')->eq('projectdoc')->fetchPairs('id', 'name'); - } -} + + * @package doc + * @version $Id: model.php 881 2010-06-22 06:50:32Z chencongzhi520 $ + * @link http://www.zentao.net + */ +?> +app->getModuleName(); + $currentMethod = $this->app->getMethodName(); + + $selectHtml = html::select('libID', $libs, $libID, "onchange=\"switchDocLib(this.value, '$currentModule', '$currentMethod', '$extra');\""); + common::setMenuVars($this->lang->doc->menu, 'list', $selectHtml . $this->lang->arrow); + foreach($this->lang->doc->menu as $key => $menu) + { + if($key != 'list') common::setMenuVars($this->lang->doc->menu, $key, $libID); + } + } + + /** + * Get library by id. + * + * @param int $libID + * @access public + * @return object + */ + public function getLibById($libID) + { + return $this->dao->findByID($libID)->from(TABLE_DOCLIB)->fetch(); + } + + /** + * Get libraries. + * + * @access public + * @return array + */ + public function getLibs() + { + $libs = $this->dao->select('id, name')->from(TABLE_DOCLIB)->where('deleted')->eq(0)->fetchPairs(); + return $this->lang->doc->systemLibs + $libs; + } + + /** + * Create a library. + * + * @access public + * @return void + */ + public function createLib() + { + $lib = fixer::input('post')->stripTags('name')->get(); + $this->dao->insert(TABLE_DOCLIB) + ->data($lib) + ->autoCheck() + ->batchCheck('name', 'notempty') + ->check('name', 'unique') + ->exec(); + return $this->dao->lastInsertID(); + } + + /** + * Update a library. + * + * @param int $libID + * @access public + * @return void + */ + public function updateLib($libID) + { + $libID = (int)$libID; + $oldLib = $this->getLibById($libID); + $lib = fixer::input('post')->stripTags('name')->get(); + $this->dao->update(TABLE_DOCLIB) + ->data($lib) + ->autoCheck() + ->batchCheck('name', 'notempty') + ->check('name', 'unique', "id != $libID") + ->where('id')->eq($libID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldLib, $lib); + } + + /** + * Get docs. + * + * @param int|string $libID + * @param int $productID + * @param int $projectID + * @param int $module + * @param string $orderBy + * @param object $pager + * @access public + * @return void + */ + public function getDocs($libID, $productID, $projectID, $module, $orderBy, $pager) + { + $products = $this->loadModel('product')->getPairs(); + $projects = $this->loadModel('project')->getPairs(); + $keysOfProducts = array_keys($products); + $keysOfProjects = array_keys($projects); + $allKeysOfProjects = $keysOfProjects; + $allKeysOfProjects[] = 0; + + return $this->dao->select('*')->from(TABLE_DOC) + ->where('deleted')->eq(0) + ->beginIF(is_numeric($libID))->andWhere('lib')->eq($libID)->fi() + ->beginIF($libID == 'product')->andWhere('product')->in($keysOfProducts)->andWhere('project')->in($allKeysOfProjects)->fi() + ->beginIF($libID == 'project')->andWhere('project')->in($keysOfProjects)->fi() + ->beginIF($productID > 0)->andWhere('product')->eq($productID)->fi() + ->beginIF($projectID > 0)->andWhere('project')->eq($projectID)->fi() + ->beginIF((string)$projectID == 'int')->andWhere('project')->gt(0)->fi() + ->beginIF($module)->andWhere('module')->in($module)->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } + + /** + * Get doc info by id. + * + * @param int $docID + * @access public + * @return void + */ + public function getById($docID) + { + $doc = $this->dao->select('*') + ->from(TABLE_DOC) + ->where('id')->eq((int)$docID) + ->fetch(); + if(!$doc) return false; + $doc->content = $this->loadModel('file')->setImgSize($doc->content); + $doc->files = $this->loadModel('file')->getByObject('doc', $docID); + + $doc->libName = ''; + $doc->productName = ''; + $doc->projectName = ''; + $doc->moduleName = ''; + if($doc->lib) $doc->libName = $this->dao->findByID($doc->lib)->from(TABLE_DOCLIB)->fetch('name'); + if($doc->product) $doc->productName = $this->dao->findByID($doc->product)->from(TABLE_PRODUCT)->fetch('name'); + if($doc->project) $doc->projectName = $this->dao->findByID($doc->project)->from(TABLE_PROJECT)->fetch('name'); + if($doc->module) $doc->moduleName = $this->dao->findByID($doc->module)->from(TABLE_MODULE)->fetch('name'); + return $doc; + } + + /** + * Create a doc. + * + * @access public + * @return void + */ + public function create() + { + $now = helper::now(); + $doc = fixer::input('post') + ->add('addedBy', $this->app->user->account) + ->add('addedDate', $now) + ->setDefault('product, project, module', 0) + ->specialChars('title, digest, keywords') + ->encodeURL('url') + ->cleanInt('product, project, module') + ->remove('files, labels') + ->get(); + $condition = "lib = '$doc->lib' AND module = $doc->module"; + $this->dao->insert(TABLE_DOC) + ->data($doc) + ->autoCheck() + ->batchCheck($this->config->doc->create->requiredFields, 'notempty') + ->check('title', 'unique', $condition) + ->exec(); + if(!dao::isError()) + { + $docID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('doc', $docID); + return $docID; + } + return false; + } + + /** + * Update a doc. + * + * @param int $docID + * @access public + * @return void + */ + public function update($docID) + { + $oldDoc = $this->getById($docID); + $now = helper::now(); + $doc = fixer::input('post') + ->cleanInt('module') + ->setDefault('module', 0) + ->specialChars('title, digest, keywords') + ->encodeURL('url') + ->remove('comment,files, labels') + ->add('editedBy', $this->app->user->account) + ->add('editedDate', $now) + ->get(); + + $condition = "lib = '$doc->lib' AND module = $doc->module AND id != $docID"; + $this->dao->update(TABLE_DOC)->data($doc) + ->autoCheck() + ->batchCheck($this->config->doc->edit->requiredFields, 'notempty') + ->check('title', 'unique', $condition) + ->where('id')->eq((int)$docID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldDoc, $doc); + } + + /** + * Get docs of a product. + * + * @param int $productID + * @access public + * @return array + */ + public function getProductDocs($productID) + { + return $this->dao->select('t1.*, t2.name as module') + ->from(TABLE_DOC)->alias('t1') + ->leftjoin(TABLE_MODULE)->alias('t2')->on('t1.module = t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('t1.id_desc') + ->fetchAll(); + } + + /** + * Get docs of a project. + * + * @param int $projectID + * @access public + * @return array + */ + public function getProjectDocs($projectID) + { + return $this->dao->findByProject($projectID)->from(TABLE_DOC)->andWhere('deleted')->eq(0)->orderBy('id_desc')->fetchAll(); + } + + /** + * Get pairs of product modules. + * + * @access public + * @return array + */ + public function getProductModulePairs() + { + return $this->dao->findByType('productdoc')->from(TABLE_MODULE)->fetchPairs('id', 'name'); + } + + /** + * Get pairs of project modules. + * + * @access public + * @return array + */ + public function getProjectModulePairs() + { + return $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->andWhere('type')->eq('projectdoc')->fetchPairs('id', 'name'); + } +} diff --git a/module/doc/view/browse.html.php b/module/doc/view/browse.html.php index edb2542029..45dedcf93c 100644 --- a/module/doc/view/browse.html.php +++ b/module/doc/view/browse.html.php @@ -1,82 +1,82 @@ - - * @package lib - * @version $Id: browse.html.php 958 2010-07-22 08:09:42Z wwccss $ - * @link http://www.zentao.net - */ -?> - - - - -
      - -
      - doc->create);?> -
      -
      -
      '>
      - - - - - - - -
      -
      -
      - -
      - tree->docManage);?> -
      -
      -
      - - - - recTotal}&recPerPage={$pager->recPerPage}";?> - - - - - - - - - - $doc):?> - createLink('doc', 'view', "docID=$doc->id"); - $canView = common::hasPriv('doc', 'view'); - ?> - - - - - - - - - - - -
      idAB);?>doc->title);?>doc->type);?>doc->addedBy);?>doc->addedDate);?>actions;?>
      id)); else printf('%03d', $doc->id);?>title);?>doc->types[$doc->type];?>addedBy]) ? print($users[$doc->addedBy]) : print($doc->addedBy);?>addedDate));?> - id}"; - if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; - if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; - ?> -
      show();?>
      -
      - + + * @package lib + * @version $Id: browse.html.php 958 2010-07-22 08:09:42Z wwccss $ + * @link http://www.zentao.net + */ +?> + + + + +
      + +
      + doc->create);?> +
      +
      +
      '>
      + + + + + + + +
      +
      +
      + +
      + tree->docManage);?> +
      +
      +
      + + + + recTotal}&recPerPage={$pager->recPerPage}";?> + + + + + + + + + + $doc):?> + createLink('doc', 'view', "docID=$doc->id"); + $canView = common::hasPriv('doc', 'view'); + ?> + + + + + + + + + + + +
      idAB);?>doc->title);?>doc->type);?>doc->addedBy);?>doc->addedDate);?>actions;?>
      id)); else printf('%03d', $doc->id);?>title);?>doc->types[$doc->type];?>addedBy]) ? print($users[$doc->addedBy]) : print($doc->addedBy);?>addedDate));?> + id}"; + if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; + if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; + ?> +
      show();?>
      +
      + diff --git a/module/doc/view/create.html.php b/module/doc/view/create.html.php index 4d47319629..c8f1f2c46e 100644 --- a/module/doc/view/create.html.php +++ b/module/doc/view/create.html.php @@ -1,70 +1,70 @@ - - * @package doc - * @version $Id: create.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      doc->create;?>
      doc->product;?>
      doc->project;?>
      doc->product;?>
      doc->module;?>
      doc->type;?>doc->types, 'file', "onclick=setType(this.value)");?>
      doc->title;?>
      doc->keywords;?>
      doc->digest;?>
      doc->files;?>fetch('file', 'buildform', 'fileCount=2');?>
      -
      - + + * @package doc + * @version $Id: create.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      doc->create;?>
      doc->product;?>
      doc->project;?>
      doc->product;?>
      doc->module;?>
      doc->type;?>doc->types, 'file', "onclick=setType(this.value)");?>
      doc->title;?>
      doc->keywords;?>
      doc->digest;?>
      doc->files;?>fetch('file', 'buildform', 'fileCount=2');?>
      +
      + diff --git a/module/doc/view/createlib.html.php b/module/doc/view/createlib.html.php index ca0cd3b918..da2f773981 100644 --- a/module/doc/view/createlib.html.php +++ b/module/doc/view/createlib.html.php @@ -1,26 +1,26 @@ - - * @package doc - * @version $Id: createlib.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
      - - - - - - - - - -
      doc->createLib;?>
      doc->libName;?>
      -
      - + + * @package doc + * @version $Id: createlib.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
      + + + + + + + + + +
      doc->createLib;?>
      doc->libName;?>
      +
      + diff --git a/module/doc/view/edit.html.php b/module/doc/view/edit.html.php index 75bbfd050b..260e89126b 100644 --- a/module/doc/view/edit.html.php +++ b/module/doc/view/edit.html.php @@ -1,68 +1,68 @@ - - * @package doc - * @version $Id: edit.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - - -
      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      doc->edit;?>
      doc->module;?>module, "class='select-3'");?>
      doc->type;?>doc->types[$doc->type];?>
      doc->title;?>title, "class='text-1'");?>
      doc->keywords;?>keywords, "class='text-1'");?>
      doc->digest;?>digest, "class='text-1' rows=3");?>
      doc->comment;?>
      - - product) . html::hidden('project', $doc->project);?> -
      -
      - + + * @package doc + * @version $Id: edit.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      doc->edit;?>
      doc->module;?>module, "class='select-3'");?>
      doc->type;?>doc->types[$doc->type];?>
      doc->title;?>title, "class='text-1'");?>
      doc->keywords;?>keywords, "class='text-1'");?>
      doc->digest;?>digest, "class='text-1' rows=3");?>
      doc->comment;?>
      + + product) . html::hidden('project', $doc->project);?> +
      +
      + diff --git a/module/doc/view/editlib.html.php b/module/doc/view/editlib.html.php index 160f3f0a1b..72840811b5 100644 --- a/module/doc/view/editlib.html.php +++ b/module/doc/view/editlib.html.php @@ -1,28 +1,28 @@ - - * @package doc - * @version $Id: editlib.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - -

      doc->errorEditSystemDoc;?>

      - -
      - - - - - - - -
      doc->editLib;?>
      doc->libName;?>
      -
      - - + + * @package doc + * @version $Id: editlib.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + +

      doc->errorEditSystemDoc;?>

      + +
      + + + + + + + +
      doc->editLib;?>
      doc->libName;?>
      +
      + + diff --git a/module/doc/view/view.html.php b/module/doc/view/view.html.php index a92b88dff1..368263e1e3 100644 --- a/module/doc/view/view.html.php +++ b/module/doc/view/view.html.php @@ -1,75 +1,75 @@ - - * @package doc - * @version $Id: view.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      title . $lang->colon . $lang->doc->view;?>
      doc->title;?>deleted) echo "class='deleted'";?>>title;?>
      doc->lib;?>
      doc->module;?>moduleName;?>
      doc->type;?>doc->types[$doc->type];?>
      doc->title;?>title;?>
      doc->keywords;?>keywords;?>
      doc->digest;?>digest);?>
      -
      - session->docList ? $this->session->docList : inlink('browse'); - if(!$doc->deleted) - { - common::printLink('doc', 'edit', "docID=$doc->id", $lang->edit); - common::printLink('doc', 'delete', "docID=$doc->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
      - - + + * @package doc + * @version $Id: view.html.php 975 2010-07-29 03:30:25Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      title . $lang->colon . $lang->doc->view;?>
      doc->title;?>deleted) echo "class='deleted'";?>>title;?>
      doc->lib;?>
      doc->module;?>moduleName;?>
      doc->type;?>doc->types[$doc->type];?>
      doc->title;?>title;?>
      doc->keywords;?>keywords;?>
      doc->digest;?>digest);?>
      +
      + session->docList ? $this->session->docList : inlink('browse'); + if(!$doc->deleted) + { + common::printLink('doc', 'edit', "docID=$doc->id", $lang->edit); + common::printLink('doc', 'delete', "docID=$doc->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
      + + diff --git a/module/editor/control.php b/module/editor/control.php index c87c7070f6..0470e2ce7e 100644 --- a/module/editor/control.php +++ b/module/editor/control.php @@ -1,164 +1,164 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -class editor extends control -{ - /** - * Show module files and edit them. - * - * @access public - * @return void - */ - public function index() - { - $this->view->moduleList = $this->editor->getModules(); - $this->display(); - } - - /** - * Show this module of files. - * - * @param string $moduleDir - * @access public - * @return void - */ - public function extend($moduleDir = '') - { - $moduleFiles = $this->editor->getModuleFiles($moduleDir); - $this->view->module = $moduleDir; - $this->view->tree = $this->editor->printTree($moduleFiles); - $this->display(); - } - - /** - * Edit extend. - * - * @param string $filePath - * @param string $action - * @param string $isExtends - * @access public - * @return void - */ - public function edit($filePath = '', $action = '', $isExtends = '') - { - $this->view->safeFilePath = $filePath; - $fileContent = ''; - if($filePath) - { - $filePath = helper::safe64Decode($filePath); - if($action == 'extendOther' and file_exists($filePath)) - { - $this->view->showContent = htmlspecialchars(file_get_contents($filePath)); - } - if($action == 'edit' or $action == 'override') - { - if(file_exists($filePath)) - { - $fileContent = file_get_contents($filePath); - if($action == 'override') - { - $fileContent = str_replace('../../', '../../../', $fileContent); - $fileContent = str_replace(array('\'./', '"./'), array('\'../../view/', '"../../view'), $fileContent); - } - } - else - { - $filePath = ''; - } - } - elseif($action == 'extendModel') - { - $fileContent = $this->editor->extendModel($filePath); - } - elseif($action == 'extendControl') - { - $okUrl = $this->editor->getExtendLink($filePath, 'extendControl', 'yes'); - $cancelUrl = $this->editor->getExtendLink($filePath, 'extendControl', 'no'); - if(!$isExtends) die(js::confirm($this->lang->editor->extendConfirm, $okUrl, $cancelUrl)); - $fileContent = $this->editor->extendControl($filePath, $isExtends); - } - elseif($action == 'newPage') - { - $fileContent = $this->editor->newControl($filePath); - } - elseif(strrpos(basename($filePath), '.php') !== false and empty($fileContent)) - { - $fileContent = "view->fileContent = $fileContent; - $this->view->filePath = $filePath; - $this->view->action = $action; - $this->display(); - } - - /** - * Set Page name. - * - * @param string $filePath - * @access public - * @return void - */ - public function newPage($filePath) - { - $filePath = helper::safe64Decode($filePath); - if($_POST) - { - $saveFilePath = $this->editor->getSavePath($filePath, 'newMethod'); - $extendLink = $this->editor->getExtendLink($saveFilePath, 'newPage'); - if(file_exists($saveFilePath) and !$this->post->override) die(js::confirm($this->lang->editor->repeatPage, $extendLink, '', 'parent')); - die(js::locate($extendLink, 'parent')); - } - $this->view->filePath = $filePath; - $this->display(); - } - - /** - * Save file to extension. - * - * @param string $filePath - * @access public - * @return void - */ - public function save($filePath = '', $action = '') - { - if($filePath and $_POST) - { - $filePath = helper::safe64Decode($filePath); - if($action != 'edit' and $action != 'newPage') $filePath = $this->editor->getSavePath($filePath, $action); - if($action != 'edit' and $action != 'newPage' and file_exists($filePath) and !$this->post->override) die(js::error($this->lang->editor->repeatFile)); - $this->editor->save($filePath); - echo js::reload('parent.parent.extendWin'); - die(js::locate(inlink('edit', "filePath=" . helper::safe64Encode($filePath) . "&action=edit"), 'parent')); - } - } - - /** - * Delete extension file. - * - * @param string $filePath - * @param string $confirm - * @access public - * @return void - */ - public function delete($filePath = '', $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->editor->deleteConfirm, inlink('delete', "filePath=$filePath&confirm=yes"))); - } - $filePath = helper::safe64Decode($filePath); - if(file_exists($filePath) and unlink($filePath)) die(js::reload('parent')); - die(js::alert($this->lang->editor->notDelete)); - - } -} - + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +class editor extends control +{ + /** + * Show module files and edit them. + * + * @access public + * @return void + */ + public function index() + { + $this->view->moduleList = $this->editor->getModules(); + $this->display(); + } + + /** + * Show this module of files. + * + * @param string $moduleDir + * @access public + * @return void + */ + public function extend($moduleDir = '') + { + $moduleFiles = $this->editor->getModuleFiles($moduleDir); + $this->view->module = $moduleDir; + $this->view->tree = $this->editor->printTree($moduleFiles); + $this->display(); + } + + /** + * Edit extend. + * + * @param string $filePath + * @param string $action + * @param string $isExtends + * @access public + * @return void + */ + public function edit($filePath = '', $action = '', $isExtends = '') + { + $this->view->safeFilePath = $filePath; + $fileContent = ''; + if($filePath) + { + $filePath = helper::safe64Decode($filePath); + if($action == 'extendOther' and file_exists($filePath)) + { + $this->view->showContent = htmlspecialchars(file_get_contents($filePath)); + } + if($action == 'edit' or $action == 'override') + { + if(file_exists($filePath)) + { + $fileContent = file_get_contents($filePath); + if($action == 'override') + { + $fileContent = str_replace('../../', '../../../', $fileContent); + $fileContent = str_replace(array('\'./', '"./'), array('\'../../view/', '"../../view'), $fileContent); + } + } + else + { + $filePath = ''; + } + } + elseif($action == 'extendModel') + { + $fileContent = $this->editor->extendModel($filePath); + } + elseif($action == 'extendControl') + { + $okUrl = $this->editor->getExtendLink($filePath, 'extendControl', 'yes'); + $cancelUrl = $this->editor->getExtendLink($filePath, 'extendControl', 'no'); + if(!$isExtends) die(js::confirm($this->lang->editor->extendConfirm, $okUrl, $cancelUrl)); + $fileContent = $this->editor->extendControl($filePath, $isExtends); + } + elseif($action == 'newPage') + { + $fileContent = $this->editor->newControl($filePath); + } + elseif(strrpos(basename($filePath), '.php') !== false and empty($fileContent)) + { + $fileContent = "view->fileContent = $fileContent; + $this->view->filePath = $filePath; + $this->view->action = $action; + $this->display(); + } + + /** + * Set Page name. + * + * @param string $filePath + * @access public + * @return void + */ + public function newPage($filePath) + { + $filePath = helper::safe64Decode($filePath); + if($_POST) + { + $saveFilePath = $this->editor->getSavePath($filePath, 'newMethod'); + $extendLink = $this->editor->getExtendLink($saveFilePath, 'newPage'); + if(file_exists($saveFilePath) and !$this->post->override) die(js::confirm($this->lang->editor->repeatPage, $extendLink, '', 'parent')); + die(js::locate($extendLink, 'parent')); + } + $this->view->filePath = $filePath; + $this->display(); + } + + /** + * Save file to extension. + * + * @param string $filePath + * @access public + * @return void + */ + public function save($filePath = '', $action = '') + { + if($filePath and $_POST) + { + $filePath = helper::safe64Decode($filePath); + if($action != 'edit' and $action != 'newPage') $filePath = $this->editor->getSavePath($filePath, $action); + if($action != 'edit' and $action != 'newPage' and file_exists($filePath) and !$this->post->override) die(js::error($this->lang->editor->repeatFile)); + $this->editor->save($filePath); + echo js::reload('parent.parent.extendWin'); + die(js::locate(inlink('edit', "filePath=" . helper::safe64Encode($filePath) . "&action=edit"), 'parent')); + } + } + + /** + * Delete extension file. + * + * @param string $filePath + * @param string $confirm + * @access public + * @return void + */ + public function delete($filePath = '', $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->editor->deleteConfirm, inlink('delete', "filePath=$filePath&confirm=yes"))); + } + $filePath = helper::safe64Decode($filePath); + if(file_exists($filePath) and unlink($filePath)) die(js::reload('parent')); + die(js::alert($this->lang->editor->notDelete)); + + } +} + diff --git a/module/editor/model.php b/module/editor/model.php index 838b725124..4dd6337656 100644 --- a/module/editor/model.php +++ b/module/editor/model.php @@ -1,561 +1,561 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -class editorModel extends model -{ - private $pathFix = DIRECTORY_SEPARATOR; - - /** - * Get all modules - * - * @access public - * @return string - */ - public function getModules() - { - $modules = glob($this->app->getModuleRoot() . '*'); - $moduleList = '
        '; - foreach($modules as $module) - { - $module = basename($module); - if($module == 'editor' or $module == 'help' or $module == 'setting') continue; - $moduleName = !empty($this->lang->editor->modules[$module]) ? $this->lang->editor->modules[$module] : $module; - $moduleList .= '
      • ' . html::a(inlink('extend', "moduleDir=$module"), $moduleName, 'extendWin') . '
      • '; - } - $moduleList .= '
      '; - return $moduleList; - } - - /** - * Get module files, contain control's methods and model's method but except ext. - * - * @access public - * @return array - */ - public function getModuleFiles($moduleDir) - { - $moduleRoot = $this->app->getModuleRoot(); - $moduleFullDir = $moduleRoot . $moduleDir; - $moduleFiles = scandir($moduleFullDir); - foreach($moduleFiles as $moduleFile) - { - if($moduleFile == '.' or $moduleFile == '..' or $moduleFile == '.svn') continue; - $moduleFullFile = $moduleFullDir . $this->pathFix . $moduleFile; - if($moduleFile == 'control.php' or $moduleFile == 'model.php') - { - $allModules[$moduleFullDir][$moduleFullFile] = $this->analysis($moduleFullFile); - } - elseif($moduleFile == 'ext') - { - $allModules[$moduleFullDir][$moduleFullFile] = $this->getExtensionFiles($moduleFullFile); - } - elseif(is_dir($moduleFullFile)) - { - $ext = ($moduleFile == 'js' or $moduleFile == 'css') ? $moduleFile : 'php'; - foreach(glob($moduleFullFile . $this->pathFix . "*.$ext") as $fileName) $allModules[$moduleFullDir][$moduleFullFile][$fileName] = basename($fileName); - } - else - { - $allModules[$moduleFullDir][$moduleFullFile] = $moduleFile; - } - } - $allModules = $this->sortModule($moduleFullDir, $allModules); - return $allModules; - } - - /** - * Get extension files. - * - * @param int $extPath - * @access public - * @return void - */ - public function getExtensionFiles($extPath) - { - $extensionList = array(); - $extensionDirs = scandir($extPath); - foreach($extensionDirs as $extensionDir) - { - if($extensionDir == '.' or $extensionDir == '..' or $extensionDir == '.svn') continue; - $extensionFullDir = $extPath . $this->pathFix . $extensionDir; - if(is_dir($extensionFullDir)) - { - $extensionList[$extensionFullDir] = array(); - /* extend of lang is more a grade of directroy. */ - if($extensionDir == 'lang' or $extensionDir == 'js' or $extensionDir == 'css') - { - - $extensionList[$extensionFullDir] = $this->getTwoGradeFiles($extensionFullDir); - continue; - } - $extensionFiles = scandir($extensionFullDir); - foreach($extensionFiles as $extensionFile) - { - if($extensionFile == '.' or $extensionFile == '..' or $extensionFile == '.svn') continue; - $extensionFullFile = $extensionFullDir . $this->pathFix . $extensionFile; - $extensionList[$extensionFullDir][$extensionFullFile] = $extensionFile; - } - } - } - $extensionList = $this->sortModule($extPath, $extensionList, true); - return $extensionList; - } - - /** - * Sort module - * - * @param string $filePath - * @param string $moduleFiles - * @param bool $isExtension - * @access public - * @return array - */ - public function sortModule($filePath, $moduleFiles, $isExtension = false) - { - $sort = $isExtension ? 'extSort' : 'sort'; - $sortModules = array(); - if(!$isExtension) $moduleFiles = $moduleFiles[$filePath]; - foreach($this->config->editor->$sort as $sort) - { - $sortKey = empty($sort) ? $filePath : $filePath . $this->pathFix . $sort; - if(array_key_exists($sortKey, $moduleFiles)) $sortModules[$sortKey] = $moduleFiles[$sortKey]; - } - return $sortModules; - } - - /** - * if a directory has two grage, this method will get files - * - * @param string $extensionFullDir - * @access public - * @return string - */ - public function getTwoGradeFiles($extensionFullDir) - { - $fileList = array(); - $langDirs = scandir($extensionFullDir); - foreach($langDirs as $langDir) - { - if($langDir == '.' or $langDir == '..' or $langDir == '.svn') continue; - $langFullDir = $extensionFullDir . $this->pathFix . $langDir; - $fileList[$langFullDir] = array(); - if(is_dir($langFullDir)) - { - $langFiles = scandir($langFullDir); - foreach($langFiles as $langFile) - { - if($langFile == '.' or $langFile == '..' or $langFile == '.svn') continue; - $langFullFile = $langFullDir . $this->pathFix . $langFile; - $fileList[$langFullDir][$langFullFile] = $langFile; - } - } - } - return $fileList; - } - - /** - * Analysis methods of control and model. - * - * @param string $fileName - * @access public - * @return array - */ - public function analysis($fileName) - { - $classMethod = array(); - $class = strstr($fileName, $this->pathFix . 'module' . $this->pathFix); - $class = substr($class, 0, strpos($class, $this->pathFix, 9)); - $class = basename($class); - if(strpos($fileName, 'model.php') !== false) $class .= 'Model'; - if(!class_exists($class)) include $fileName; - $reflection = new ReflectionClass($class); - foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) - { - $methodName = $method->name; - if($method->getFileName() != $fileName) continue; - if($methodName == '__construct') continue; - $classMethod[$fileName . $this->pathFix . $methodName] = $methodName; - } - return $classMethod; - } - - /** - * Print tree from module files. - * - * @param int $files - * @access public - * @return void - */ - public function printTree($files, $isRoot = true) - { - if(empty($files) or !is_array($files)) return false; - $tree = $isRoot ? "
        \n" : "
          \n"; - if($isRoot) - { - $langFile = dirname(key($files)) . $this->pathFix . 'lang' . $this->pathFix . $this->cookie->lang. '.php'; - if(file_exists($langFile)) include_once $langFile; - $module = basename(dirname(key($files))); - if(isset($lang->$module)) - { - $this->module = $lang->$module; - } - elseif(isset($this->lang->$module)) - { - $this->module = $this->lang->$module; - } - else - { - $this->module = ''; - } - } - foreach($files as $key => $file) - { - $tree .= "
        • \n"; - if(is_array($file)) - { - $tree .= $this->addLink4Dir($key); - $tree .= $this->printTree($file, false); - } - else - { - $tree .= $this->addLink4File($key, $file); - } - $tree .= "
        • \n"; - } - $tree .= "
        \n"; - return $tree; - } - - /** - * Add link for directory or has children grade - * - * @param string $filePath - * @access public - * @return string - */ - public function addLink4Dir($filePath) - { - $tree = ''; - $fileName = basename($filePath); - if(isset($this->lang->editor->modules[$fileName])) - { - $file = "" . $this->lang->editor->modules[$fileName] . ''; - } - elseif(isset($this->lang->editor->translate[$fileName])) - { - $file = "" . $this->lang->editor->translate[$fileName] . ''; - } - else - { - $file = "$fileName"; - } - if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false) - { - switch($fileName) - { - case 'lang': $tree .= $file; break; - case 'js': $tree .= "$file " . html::a($this->getExtendLink($filePath, "newJS"), $this->lang->editor->newExtend, 'editWin'); break; - case 'css': $tree .= "$file " . html::a($this->getExtendLink($filePath, "newCSS"), $this->lang->editor->newExtend, 'editWin'); break; - default: $tree .= "$file " . html::a($this->getExtendLink($filePath, "newExtend"), $this->lang->editor->newExtend, 'editWin'); - } - } - elseif($fileName == 'model.php') - { - $tree .= "$file " . html::a($this->getExtendLink($filePath, 'newMethod'), $this->lang->editor->newMethod, 'editWin'); - } - elseif($fileName == 'control.php') - { - $tree .= "$file " . html::a(inlink('newPage', "filePath=" . helper::safe64Encode($filePath)), $this->lang->editor->newPage, 'editWin'); - } - else - { - $tree .= $file; - } - return $tree; - } - - /** - * Add link for file - * - * @param string $filePath - * @param string $file - * @access public - * @return string - */ - public function addLink4File($filePath, $file) - { - $tree = ''; - if(isset($this->module->$file) and !is_object($this->module->$file) and !is_array($this->module->$file)) - { - $file = "" . $this->module->$file . ''; - } - elseif(isset($this->lang->editor->translate[$file])) - { - if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false and $file == 'config.php') - { - $file = "$file"; - } - else - { - $file = "" . $this->lang->editor->translate[$file] . ''; - } - } - else - { - $file = "$file"; - } - if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false) - { - $tree .= "$file " . html::a($this->getExtendLink($filePath, "edit"), $this->lang->edit, 'editWin'); - $tree .= html::a(inlink('delete', 'path=' . helper::safe64Encode($filePath)), $this->lang->delete, 'hiddenwin') . "\n"; - } - elseif(basename(dirname($filePath))== 'view') - { - $tree .= "$file " . html::a($this->getExtendLink($filePath, "override"), $this->lang->editor->override, 'editWin'); - $tree .= html::a($this->getExtendLink($filePath, "newHook"), $this->lang->editor->newHook, 'editWin') . "\n"; - } - else - { - $parentDir = basename(dirname($filePath)); - $action = 'extendOther'; - if($parentDir == 'control.php') $action = 'extendControl'; - if($parentDir == 'model.php') $action = 'extendModel'; - $tree .= "$file " . html::a($this->getExtendLink($filePath, $action), $this->lang->editor->extend, 'editWin'); - if($parentDir == 'lang') $tree .= html::a($this->getExtendLink($filePath, "new" . str_replace('-', '_', basename($filePath, '.php'))), $this->lang->editor->newLang, 'editWin'); - if(basename($filePath) == 'config.php') $tree .= html::a($this->getExtendLink($filePath, "newConfig"), $this->lang->editor->newConfig, 'editWin'); - } - return $tree; - } - - /** - * Get extend link - * - * @param string $filePath - * @param string $action - * @param string $isExtends - * @access public - * @return string - */ - public function getExtendLink($filePath, $action, $isExtends = '') - { - return inlink('edit', "filePath=" . helper::safe64Encode($filePath) . "&action=$action&isExtends=$isExtends"); - } - - /** - * Save file to extension. - * - * @param string $filePath - * @access public - * @return void - */ - public function save($filePath) - { - $fileContent = $this->post->fileContent; - if(get_magic_quotes_gpc()) $fileContent = stripslashes($fileContent); - $dirPath = dirname($filePath); - $extFilePath = substr($filePath, 0, strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) + 4); - if(!is_dir($dirPath) and is_writable($extFilePath)) mkdir($dirPath, 0777, true); - if(is_writable($dirPath)) - { - file_put_contents($filePath, $fileContent); - } - else - { - die(js::alert($this->lang->editor->notWritable . $extFilePath)); - } - } - - /** - * Extend model.php and get file content. - * - * @param string $filePath - * @access public - * @return string - */ - public function extendModel($filePath) - { - $className = basename(dirname(dirname($filePath))); - if(!class_exists($className)) include(dirname($filePath)); - $methodName = basename($filePath); - $methodParam = $this->getParam($className, $methodName, 'Model'); - return $fileContent = <<getParam($className, $methodName); - return $fileContent = <<getMethodCode($className, $methodName); - return $fileContent = <<pathFix . 'module' . $this->pathFix); - $className = substr($className, 0, strpos($className, $this->pathFix, 9)); - $className = basename($className); - $methodName = basename($filePath, '.php'); - return $fileContent = <<getParameters() as $param) - { - $methodParam .= '$' . $param->getName(); - if($param->isOptional()) - { - $defaultParam = $param->getDefaultValue(); - if(is_string($defaultParam)) $methodParam .= "='$defaultParam', "; - else $methodParam .= "=$defaultParam, "; - } - else - { - $methodParam .= ', '; - } - } - $methodParam = rtrim($methodParam, ', '); - return $methodParam; - } - - /** - * Get method code. - * - * @param string $className - * @param string $methodName - * @param string $ext value may be Model - * @access public - * @return string - */ - public function getMethodCode($className, $methodName, $ext = '') - { - $method = new ReflectionMethod($className . $ext, $methodName); - $fileName = $method->getFileName(); - $startLine = $method->getStartLine(); - $endLine = $method->getEndLine(); - $file = file($fileName); - $code = ''; - for($i = $startLine - 1; $i <= $endLine; $i++) - { - $code .= $file[$i]; - } - return $code; - } - - /** - * Get save path. - * - * @param string $filePath - * @param string $action - * @access public - * @return string - */ - public function getSavePath($filePath, $action) - { - $fileName = empty($_POST['fileName']) ? '' : trim($this->post->fileName); - $moduleName = strstr($filePath, $this->pathFix . 'module' . $this->pathFix); - $moduleName = substr($moduleName, 0, strpos($moduleName, $this->pathFix, 9)); - $moduleName = basename($moduleName); - $extPath = $this->app->getModuleRoot() . $moduleName . $this->pathFix . 'ext' . $this->pathFix; - switch($action) - { - case 'extendModel': - $fileName = empty($fileName) ? strtolower(basename($filePath)) . '.php' : $fileName; - return $extPath . 'model' . $this->pathFix . $fileName; - case 'extendControl': - $fileName = strtolower(basename($filePath)) . '.php'; - return $extPath . 'control' . $this->pathFix . $fileName; - case 'override': - $fileName = basename($filePath); - return $extPath . 'view' . $this->pathFix . $fileName; - case 'extendOther': - $editName = basename($filePath); - $fileName = empty($fileName) ? $editName: $fileName; - if($editName == 'config.php') return $extPath . 'config' .$this->pathFix . $fileName; - elseif(strpos($editName, '.php') !== false) return $extPath . 'lang' . $this->pathFix . str_replace('.php', '', $editName) . $this->pathFix . $fileName; - else return $extPath . substr($editName, strrpos($editName, '.') + 1) . $this->pathFix . substr($editName, 0, strrpos($editName, '.')) . $this->pathFix . $fileName; - default: - if(empty($fileName)) die(js::error($this->lang->editor->emptyFileName)); - $action = strtolower(str_replace('new', '', $action)); - if($action == 'hook') return $extPath . 'view' . $this->pathFix . $fileName; - elseif($action == 'method') return $extPath . basename($filePath, '.php') . $this->pathFix . $fileName; - elseif($action == 'extend') return $filePath . $this->pathFix . $fileName; - elseif($action == 'config') return $extPath . 'config' . $this->pathFix . $fileName; - elseif($action == 'js') return $extPath . 'js' . $this->pathFix . substr($fileName, 0, strrpos($fileName, '.')) . $this->pathFix . $fileName; - elseif($action == 'css') return $extPath . 'css' . $this->pathFix . substr($fileName, 0, strrpos($fileName, '.')) . $this->pathFix . $fileName; - else return $extPath . 'lang' . $this->pathFix . str_replace('_', '-', $action) . $this->pathFix . $fileName; - } - } -} + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +class editorModel extends model +{ + private $pathFix = DIRECTORY_SEPARATOR; + + /** + * Get all modules + * + * @access public + * @return string + */ + public function getModules() + { + $modules = glob($this->app->getModuleRoot() . '*'); + $moduleList = '
          '; + foreach($modules as $module) + { + $module = basename($module); + if($module == 'editor' or $module == 'help' or $module == 'setting') continue; + $moduleName = !empty($this->lang->editor->modules[$module]) ? $this->lang->editor->modules[$module] : $module; + $moduleList .= '
        • ' . html::a(inlink('extend', "moduleDir=$module"), $moduleName, 'extendWin') . '
        • '; + } + $moduleList .= '
        '; + return $moduleList; + } + + /** + * Get module files, contain control's methods and model's method but except ext. + * + * @access public + * @return array + */ + public function getModuleFiles($moduleDir) + { + $moduleRoot = $this->app->getModuleRoot(); + $moduleFullDir = $moduleRoot . $moduleDir; + $moduleFiles = scandir($moduleFullDir); + foreach($moduleFiles as $moduleFile) + { + if($moduleFile == '.' or $moduleFile == '..' or $moduleFile == '.svn') continue; + $moduleFullFile = $moduleFullDir . $this->pathFix . $moduleFile; + if($moduleFile == 'control.php' or $moduleFile == 'model.php') + { + $allModules[$moduleFullDir][$moduleFullFile] = $this->analysis($moduleFullFile); + } + elseif($moduleFile == 'ext') + { + $allModules[$moduleFullDir][$moduleFullFile] = $this->getExtensionFiles($moduleFullFile); + } + elseif(is_dir($moduleFullFile)) + { + $ext = ($moduleFile == 'js' or $moduleFile == 'css') ? $moduleFile : 'php'; + foreach(glob($moduleFullFile . $this->pathFix . "*.$ext") as $fileName) $allModules[$moduleFullDir][$moduleFullFile][$fileName] = basename($fileName); + } + else + { + $allModules[$moduleFullDir][$moduleFullFile] = $moduleFile; + } + } + $allModules = $this->sortModule($moduleFullDir, $allModules); + return $allModules; + } + + /** + * Get extension files. + * + * @param int $extPath + * @access public + * @return void + */ + public function getExtensionFiles($extPath) + { + $extensionList = array(); + $extensionDirs = scandir($extPath); + foreach($extensionDirs as $extensionDir) + { + if($extensionDir == '.' or $extensionDir == '..' or $extensionDir == '.svn') continue; + $extensionFullDir = $extPath . $this->pathFix . $extensionDir; + if(is_dir($extensionFullDir)) + { + $extensionList[$extensionFullDir] = array(); + /* extend of lang is more a grade of directroy. */ + if($extensionDir == 'lang' or $extensionDir == 'js' or $extensionDir == 'css') + { + + $extensionList[$extensionFullDir] = $this->getTwoGradeFiles($extensionFullDir); + continue; + } + $extensionFiles = scandir($extensionFullDir); + foreach($extensionFiles as $extensionFile) + { + if($extensionFile == '.' or $extensionFile == '..' or $extensionFile == '.svn') continue; + $extensionFullFile = $extensionFullDir . $this->pathFix . $extensionFile; + $extensionList[$extensionFullDir][$extensionFullFile] = $extensionFile; + } + } + } + $extensionList = $this->sortModule($extPath, $extensionList, true); + return $extensionList; + } + + /** + * Sort module + * + * @param string $filePath + * @param string $moduleFiles + * @param bool $isExtension + * @access public + * @return array + */ + public function sortModule($filePath, $moduleFiles, $isExtension = false) + { + $sort = $isExtension ? 'extSort' : 'sort'; + $sortModules = array(); + if(!$isExtension) $moduleFiles = $moduleFiles[$filePath]; + foreach($this->config->editor->$sort as $sort) + { + $sortKey = empty($sort) ? $filePath : $filePath . $this->pathFix . $sort; + if(array_key_exists($sortKey, $moduleFiles)) $sortModules[$sortKey] = $moduleFiles[$sortKey]; + } + return $sortModules; + } + + /** + * if a directory has two grage, this method will get files + * + * @param string $extensionFullDir + * @access public + * @return string + */ + public function getTwoGradeFiles($extensionFullDir) + { + $fileList = array(); + $langDirs = scandir($extensionFullDir); + foreach($langDirs as $langDir) + { + if($langDir == '.' or $langDir == '..' or $langDir == '.svn') continue; + $langFullDir = $extensionFullDir . $this->pathFix . $langDir; + $fileList[$langFullDir] = array(); + if(is_dir($langFullDir)) + { + $langFiles = scandir($langFullDir); + foreach($langFiles as $langFile) + { + if($langFile == '.' or $langFile == '..' or $langFile == '.svn') continue; + $langFullFile = $langFullDir . $this->pathFix . $langFile; + $fileList[$langFullDir][$langFullFile] = $langFile; + } + } + } + return $fileList; + } + + /** + * Analysis methods of control and model. + * + * @param string $fileName + * @access public + * @return array + */ + public function analysis($fileName) + { + $classMethod = array(); + $class = strstr($fileName, $this->pathFix . 'module' . $this->pathFix); + $class = substr($class, 0, strpos($class, $this->pathFix, 9)); + $class = basename($class); + if(strpos($fileName, 'model.php') !== false) $class .= 'Model'; + if(!class_exists($class)) include $fileName; + $reflection = new ReflectionClass($class); + foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) + { + $methodName = $method->name; + if($method->getFileName() != $fileName) continue; + if($methodName == '__construct') continue; + $classMethod[$fileName . $this->pathFix . $methodName] = $methodName; + } + return $classMethod; + } + + /** + * Print tree from module files. + * + * @param int $files + * @access public + * @return void + */ + public function printTree($files, $isRoot = true) + { + if(empty($files) or !is_array($files)) return false; + $tree = $isRoot ? "
          \n" : "
            \n"; + if($isRoot) + { + $langFile = dirname(key($files)) . $this->pathFix . 'lang' . $this->pathFix . $this->cookie->lang. '.php'; + if(file_exists($langFile)) include_once $langFile; + $module = basename(dirname(key($files))); + if(isset($lang->$module)) + { + $this->module = $lang->$module; + } + elseif(isset($this->lang->$module)) + { + $this->module = $this->lang->$module; + } + else + { + $this->module = ''; + } + } + foreach($files as $key => $file) + { + $tree .= "
          • \n"; + if(is_array($file)) + { + $tree .= $this->addLink4Dir($key); + $tree .= $this->printTree($file, false); + } + else + { + $tree .= $this->addLink4File($key, $file); + } + $tree .= "
          • \n"; + } + $tree .= "
          \n"; + return $tree; + } + + /** + * Add link for directory or has children grade + * + * @param string $filePath + * @access public + * @return string + */ + public function addLink4Dir($filePath) + { + $tree = ''; + $fileName = basename($filePath); + if(isset($this->lang->editor->modules[$fileName])) + { + $file = "" . $this->lang->editor->modules[$fileName] . ''; + } + elseif(isset($this->lang->editor->translate[$fileName])) + { + $file = "" . $this->lang->editor->translate[$fileName] . ''; + } + else + { + $file = "$fileName"; + } + if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false) + { + switch($fileName) + { + case 'lang': $tree .= $file; break; + case 'js': $tree .= "$file " . html::a($this->getExtendLink($filePath, "newJS"), $this->lang->editor->newExtend, 'editWin'); break; + case 'css': $tree .= "$file " . html::a($this->getExtendLink($filePath, "newCSS"), $this->lang->editor->newExtend, 'editWin'); break; + default: $tree .= "$file " . html::a($this->getExtendLink($filePath, "newExtend"), $this->lang->editor->newExtend, 'editWin'); + } + } + elseif($fileName == 'model.php') + { + $tree .= "$file " . html::a($this->getExtendLink($filePath, 'newMethod'), $this->lang->editor->newMethod, 'editWin'); + } + elseif($fileName == 'control.php') + { + $tree .= "$file " . html::a(inlink('newPage', "filePath=" . helper::safe64Encode($filePath)), $this->lang->editor->newPage, 'editWin'); + } + else + { + $tree .= $file; + } + return $tree; + } + + /** + * Add link for file + * + * @param string $filePath + * @param string $file + * @access public + * @return string + */ + public function addLink4File($filePath, $file) + { + $tree = ''; + if(isset($this->module->$file) and !is_object($this->module->$file) and !is_array($this->module->$file)) + { + $file = "" . $this->module->$file . ''; + } + elseif(isset($this->lang->editor->translate[$file])) + { + if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false and $file == 'config.php') + { + $file = "$file"; + } + else + { + $file = "" . $this->lang->editor->translate[$file] . ''; + } + } + else + { + $file = "$file"; + } + if(strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) !== false) + { + $tree .= "$file " . html::a($this->getExtendLink($filePath, "edit"), $this->lang->edit, 'editWin'); + $tree .= html::a(inlink('delete', 'path=' . helper::safe64Encode($filePath)), $this->lang->delete, 'hiddenwin') . "\n"; + } + elseif(basename(dirname($filePath))== 'view') + { + $tree .= "$file " . html::a($this->getExtendLink($filePath, "override"), $this->lang->editor->override, 'editWin'); + $tree .= html::a($this->getExtendLink($filePath, "newHook"), $this->lang->editor->newHook, 'editWin') . "\n"; + } + else + { + $parentDir = basename(dirname($filePath)); + $action = 'extendOther'; + if($parentDir == 'control.php') $action = 'extendControl'; + if($parentDir == 'model.php') $action = 'extendModel'; + $tree .= "$file " . html::a($this->getExtendLink($filePath, $action), $this->lang->editor->extend, 'editWin'); + if($parentDir == 'lang') $tree .= html::a($this->getExtendLink($filePath, "new" . str_replace('-', '_', basename($filePath, '.php'))), $this->lang->editor->newLang, 'editWin'); + if(basename($filePath) == 'config.php') $tree .= html::a($this->getExtendLink($filePath, "newConfig"), $this->lang->editor->newConfig, 'editWin'); + } + return $tree; + } + + /** + * Get extend link + * + * @param string $filePath + * @param string $action + * @param string $isExtends + * @access public + * @return string + */ + public function getExtendLink($filePath, $action, $isExtends = '') + { + return inlink('edit', "filePath=" . helper::safe64Encode($filePath) . "&action=$action&isExtends=$isExtends"); + } + + /** + * Save file to extension. + * + * @param string $filePath + * @access public + * @return void + */ + public function save($filePath) + { + $fileContent = $this->post->fileContent; + if(get_magic_quotes_gpc()) $fileContent = stripslashes($fileContent); + $dirPath = dirname($filePath); + $extFilePath = substr($filePath, 0, strpos($filePath, $this->pathFix . 'ext' . $this->pathFix) + 4); + if(!is_dir($dirPath) and is_writable($extFilePath)) mkdir($dirPath, 0777, true); + if(is_writable($dirPath)) + { + file_put_contents($filePath, $fileContent); + } + else + { + die(js::alert($this->lang->editor->notWritable . $extFilePath)); + } + } + + /** + * Extend model.php and get file content. + * + * @param string $filePath + * @access public + * @return string + */ + public function extendModel($filePath) + { + $className = basename(dirname(dirname($filePath))); + if(!class_exists($className)) include(dirname($filePath)); + $methodName = basename($filePath); + $methodParam = $this->getParam($className, $methodName, 'Model'); + return $fileContent = <<getParam($className, $methodName); + return $fileContent = <<getMethodCode($className, $methodName); + return $fileContent = <<pathFix . 'module' . $this->pathFix); + $className = substr($className, 0, strpos($className, $this->pathFix, 9)); + $className = basename($className); + $methodName = basename($filePath, '.php'); + return $fileContent = <<getParameters() as $param) + { + $methodParam .= '$' . $param->getName(); + if($param->isOptional()) + { + $defaultParam = $param->getDefaultValue(); + if(is_string($defaultParam)) $methodParam .= "='$defaultParam', "; + else $methodParam .= "=$defaultParam, "; + } + else + { + $methodParam .= ', '; + } + } + $methodParam = rtrim($methodParam, ', '); + return $methodParam; + } + + /** + * Get method code. + * + * @param string $className + * @param string $methodName + * @param string $ext value may be Model + * @access public + * @return string + */ + public function getMethodCode($className, $methodName, $ext = '') + { + $method = new ReflectionMethod($className . $ext, $methodName); + $fileName = $method->getFileName(); + $startLine = $method->getStartLine(); + $endLine = $method->getEndLine(); + $file = file($fileName); + $code = ''; + for($i = $startLine - 1; $i <= $endLine; $i++) + { + $code .= $file[$i]; + } + return $code; + } + + /** + * Get save path. + * + * @param string $filePath + * @param string $action + * @access public + * @return string + */ + public function getSavePath($filePath, $action) + { + $fileName = empty($_POST['fileName']) ? '' : trim($this->post->fileName); + $moduleName = strstr($filePath, $this->pathFix . 'module' . $this->pathFix); + $moduleName = substr($moduleName, 0, strpos($moduleName, $this->pathFix, 9)); + $moduleName = basename($moduleName); + $extPath = $this->app->getModuleRoot() . $moduleName . $this->pathFix . 'ext' . $this->pathFix; + switch($action) + { + case 'extendModel': + $fileName = empty($fileName) ? strtolower(basename($filePath)) . '.php' : $fileName; + return $extPath . 'model' . $this->pathFix . $fileName; + case 'extendControl': + $fileName = strtolower(basename($filePath)) . '.php'; + return $extPath . 'control' . $this->pathFix . $fileName; + case 'override': + $fileName = basename($filePath); + return $extPath . 'view' . $this->pathFix . $fileName; + case 'extendOther': + $editName = basename($filePath); + $fileName = empty($fileName) ? $editName: $fileName; + if($editName == 'config.php') return $extPath . 'config' .$this->pathFix . $fileName; + elseif(strpos($editName, '.php') !== false) return $extPath . 'lang' . $this->pathFix . str_replace('.php', '', $editName) . $this->pathFix . $fileName; + else return $extPath . substr($editName, strrpos($editName, '.') + 1) . $this->pathFix . substr($editName, 0, strrpos($editName, '.')) . $this->pathFix . $fileName; + default: + if(empty($fileName)) die(js::error($this->lang->editor->emptyFileName)); + $action = strtolower(str_replace('new', '', $action)); + if($action == 'hook') return $extPath . 'view' . $this->pathFix . $fileName; + elseif($action == 'method') return $extPath . basename($filePath, '.php') . $this->pathFix . $fileName; + elseif($action == 'extend') return $filePath . $this->pathFix . $fileName; + elseif($action == 'config') return $extPath . 'config' . $this->pathFix . $fileName; + elseif($action == 'js') return $extPath . 'js' . $this->pathFix . substr($fileName, 0, strrpos($fileName, '.')) . $this->pathFix . $fileName; + elseif($action == 'css') return $extPath . 'css' . $this->pathFix . substr($fileName, 0, strrpos($fileName, '.')) . $this->pathFix . $fileName; + else return $extPath . 'lang' . $this->pathFix . str_replace('_', '-', $action) . $this->pathFix . $fileName; + } + } +} diff --git a/module/editor/view/edit.html.php b/module/editor/view/edit.html.php index d3cd51937e..06f19b2c51 100644 --- a/module/editor/view/edit.html.php +++ b/module/editor/view/edit.html.php @@ -1,70 +1,70 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          '> - - - - - - - - - - - - - - - - -
          - {$lang->editor->filePath}"?> - -
          - " . $lang->editor->sourceFile . ''?>
          - -
          - -
          - - " . $lang->editor->fileName . ''?> - - editor->exampleHook; - } - elseif($action and $action == 'extendOther' and strpos(basename($filePath), '.js') !== false or $action == 'newJS') - { - echo $lang->editor->exampleJs; - } - elseif($action and $action == 'extendOther' and strpos(basename($filePath), '.css') !== false or $action == 'newCSS') - { - echo $lang->editor->exampleCss; - } - else - { - echo $lang->editor->examplePHP; - } - ?> - - - - editor->isOverride?> - -
          -
          - + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          '> + + + + + + + + + + + + + + + + +
          + {$lang->editor->filePath}"?> + +
          + " . $lang->editor->sourceFile . ''?>
          + +
          + +
          + + " . $lang->editor->fileName . ''?> + + editor->exampleHook; + } + elseif($action and $action == 'extendOther' and strpos(basename($filePath), '.js') !== false or $action == 'newJS') + { + echo $lang->editor->exampleJs; + } + elseif($action and $action == 'extendOther' and strpos(basename($filePath), '.css') !== false or $action == 'newCSS') + { + echo $lang->editor->exampleCss; + } + else + { + echo $lang->editor->examplePHP; + } + ?> + + + + editor->isOverride?> + +
          +
          + diff --git a/module/editor/view/extend.html.php b/module/editor/view/extend.html.php index 668d34e193..5fae8ac265 100644 --- a/module/editor/view/extend.html.php +++ b/module/editor/view/extend.html.php @@ -1,29 +1,29 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          editor->modules[$module])? $lang->editor->modules[$module] : $module;?>
          - - - - + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          editor->modules[$module])? $lang->editor->modules[$module] : $module;?>
          + + + + diff --git a/module/editor/view/index.html.php b/module/editor/view/index.html.php index 6a824817d8..873003bfef 100644 --- a/module/editor/view/index.html.php +++ b/module/editor/view/index.html.php @@ -1,24 +1,24 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          -
          editor->moduleList?>
          -
          -
          - + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          +
          editor->moduleList?>
          +
          +
          + diff --git a/module/editor/view/newpage.html.php b/module/editor/view/newpage.html.php index 66d835762c..a0062c7b95 100644 --- a/module/editor/view/newpage.html.php +++ b/module/editor/view/newpage.html.php @@ -1,33 +1,33 @@ - - * @package editor - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - -
          editor->newPage?>
          editor->filePath?>
          editor->pageName?> - editor->examplePHP; - ?> -
          -
          - + + * @package editor + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + +
          editor->newPage?>
          editor->filePath?>
          editor->pageName?> + editor->examplePHP; + ?> +
          +
          + diff --git a/module/extension/control.php b/module/extension/control.php index 7b1b75ef50..2f248aebb5 100644 --- a/module/extension/control.php +++ b/module/extension/control.php @@ -1,380 +1,380 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -class extension extends control -{ - /** - * Browse extensions. - * - * @param string $status - * @access public - * @return void - */ - public function browse($status = 'installed') - { - $extensions = $this->extension->getLocalExtensions($status); - $versions = array(); - if($extensions and $status == 'installed') - { - /* Get latest release from remote. */ - $extCodes = helper::safe64Encode(join(',', array_keys($extensions))); - $results = $this->extension->getExtensionsByAPI('bycode', $extCodes, $recTotal = 0, $recPerPage = 1000, $pageID = 1); - if(isset($results->extensions)) - { - $remoteReleases = $results->extensions; - foreach($remoteReleases as $release) - { - if(!isset($extensions[$release->code])) continue; - - $extension = $extensions[$release->code]; - $extension->viewLink = $release->viewLink; - if($extension->version != $release->latestRelease->releaseVersion and $this->extension->checkVersion($release->latestRelease->zentaoVersion)) - { - $extension->upgradeLink = ($release->latestRelease->charge or !$release->latestRelease->public) ? $release->latestRelease->downLink : inlink('upgrade', "extension=$release->code&downLink=" . helper::safe64Encode($release->latestRelease->downLink) . "&md5={$release->latestRelease->md5}&type=$release->type"); - } - } - } - } - - $this->view->header->title = $this->lang->extension->browse; - $this->view->position[] = $this->lang->extension->browse; - $this->view->tab = $status; - $this->view->extensions = $extensions; - $this->view->versions = $versions; - $this->display(); - } - - /** - * Obtain extensions from the community. - * - * @param string $type - * @param string $param - * @access public - * @return void - */ - public function obtain($type = 'byUpdatedTime', $param = '', $recTotal = 0, $recPerPage = 10, $pageID = 1) - { - /* Init vars. */ - $type = strtolower($type); - $moduleID = $type == 'bymodule' ? (int)$param : 0; - $extensions = array(); - $pager = null; - - /* Set the key. */ - if($type == 'bysearch') $param = helper::safe64Encode($this->post->key); - - /* Get results from the api. */ - $results = $this->extension->getExtensionsByAPI($type, $param, $recTotal, $recPerPage, $pageID); - if($results) - { - $this->app->loadClass('pager', $static = true); - $pager = new pager($results->dbPager->recTotal, $results->dbPager->recPerPage, $results->dbPager->pageID); - $extensions = $results->extensions; - } - - $this->view->moduleTree = $this->extension->getModulesByAPI(); - $this->view->extensions = $extensions; - $this->view->installeds = $this->extension->getLocalExtensions('installed'); - $this->view->pager = $pager; - $this->view->tab = 'obtain'; - $this->view->type = $type; - $this->view->moduleID = $moduleID; - $this->display(); - } - - /** - * Install a extension - * - * @param string $extension - * @param string $downLink - * @param string $md5 - * @param string $type - * @param string $overridePackage - * @param string $ignoreCompatible - * @param string $overrideFile - * @param string $agreeLicense - * @param int $upgrade - * @access public - * @return void - */ - public function install($extension, $downLink = '', $md5 = '', $type = '', $overridePackage = 'no', $ignoreCompatible = 'no', $overrideFile = 'no', $agreeLicense = 'no', $upgrade = 0) - { - $this->view->error = ''; - $this->view->header->title = $this->lang->extension->install . $this->lang->colon . $extension; - - /* Get the package file name. */ - $packageFile = $this->extension->getPackageFile($extension); - - if($downLink) - { - /* Checking download path. */ - $return = $this->extension->checkDownloadPath(); - if($return->result != 'ok') - { - $this->view->error = $return->error; - die($this->display()); - } - - /* Check file exists or not. */ - if(file_exists($packageFile) and $overridePackage == 'no') - { - $overrideLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=yes&ignoreCompatible=$ignoreCompatible&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); - $this->view->error = sprintf($this->lang->extension->errorPackageFileExists, $packageFile, $overrideLink); - die($this->display()); - } - - /* Download the package file. */ - $this->extension->downloadPackage($extension, helper::safe64Decode($downLink)); - if(!file_exists($packageFile)) - { - $this->view->error = sprintf($this->lang->extension->errorDownloadFailed, $packageFile); - die($this->display()); - } - elseif($md5 != '' and md5_file($packageFile) != $md5) - { - unlink($packageFile); - $this->view->error = sprintf($this->lang->extension->errorMd5Checking, $packageFile); - die($this->display()); - } - } - - /* Check the package file exists or not. */ - if(!file_exists($packageFile)) - { - $this->view->error = sprintf($this->lang->extension->errorPackageNotFound, $packageFile); - die($this->display()); - } - - /* Checking the extension pathes. */ - $return = $this->extension->checkExtensionPathes($extension); - if($this->session->dirs2Created == false) $this->session->set('dirs2Created', $return->dirs2Created); // Save the dirs to be created. - if($return->result != 'ok') - { - $this->view->error = $return->errors; - die($this->display()); - } - - /* Extract the package. */ - $return = $this->extension->extractPackage($extension); - if($return->result != 'ok') - { - $this->view->error = sprintf($this->lang->extension->errorExtracted, $packageFile, $return->error); - die($this->display()); - } - - /* Check version comptiable. */ - $zentaoVersion = $this->extension->getZentaoVersion($extension); - if(!$this->extension->checkVersion($zentaoVersion) and $ignoreCompatible == 'no') - { - $ignoreLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=yes&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); - $returnLink = inlink('obtain'); - $this->view->error = sprintf($this->lang->extension->errorCheckIncompatible, $ignoreLink, $returnLink); - die($this->display()); - } - - /* Check files in the package conflicts with exists files or not. */ - if($overrideFile == 'no') - { - $return = $this->extension->checkFile($extension); - if($return->result != 'ok') - { - $overrideLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=yes&agreeLicense=$agreeLicense&upgrade=$upgrade"); - $returnLink = inlink('obtain'); - $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $overrideLink, $returnLink); - die($this->display()); - } - } - - /* Print the license form. */ - if($agreeLicense == 'no') - { - $extensionInfo = $this->extension->getInfoFromPackage($extension); - $license = $this->extension->processLicense($extensionInfo->license); - $agreeLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=$overrideFile&agreeLicense=yes&upgrade=$upgrade"); - $this->view->license = $license; - $this->view->author = $extensionInfo->author; - $this->view->agreeLink = $agreeLink; - die($this->display()); - } - - if($upgrade) - { - $info = $this->extension->parseExtensionCFG($extension); - $this->post->upgradeVersion = isset($info->version) ? $info->version : ''; - $info = $this->extension->getInfoFromDB($extension); - $this->post->installedVersion = $info ? $info->version : ''; - } - - /* The preInstall hook file. */ - $hook = $upgrade ? 'preupgrade' : 'preinstall'; - if($preHookFile = $this->extension->getHookFile($extension, $hook)) include $preHookFile; - - /* Save to database. */ - $this->extension->saveExtension($extension, $type); - - /* Copy files to target directory. */ - $this->view->files = $this->extension->copyPackageFiles($extension); - - /* Judge need execute db install or not. */ - $data->status = 'installed'; - $data->dirs = $this->session->dirs2Created; - $data->files = $this->view->files; - $data->installedTime = helper::now(); - $this->session->set('dirs2Created', array()); // clean the session. - - /* Execute the install.sql. */ - if($this->extension->needExecuteDB($extension, 'install')) - { - $return = $this->extension->executeDB($extension, 'install'); - if($return->result != 'ok') - { - $this->view->error = sprintf($this->lang->extension->errorInstallDB, $return->error); - die($this->display()); - } - } - - /* Update status, dirs, files and installed time. */ - $this->extension->updateExtension($extension, $data); - $this->view->downloadedPackage = !empty($downLink); - - /* The postInstall hook file. */ - $hook = $upgrade ? 'postupgrade' : 'postinstall'; - if($postHookFile = $this->extension->getHookFile($extension, $hook)) include $postHookFile; - - $this->display(); - } - - /** - * Uninstall an extension. - * - * @param string $extension - * @access public - * @return void - */ - public function uninstall($extension) - { - if($preUninstallHook = $this->extension->getHookFile($extension, 'preuninstall')) include $preUninstallHook; - - $this->extension->executeDB($extension, 'uninstall'); - $this->extension->updateExtension($extension, array('status' => 'available')); - $this->view->removeCommands = $this->extension->removePackage($extension); - $this->view->header->title = $this->lang->extension->uninstallFinished; - - if($postUninstallHook = $this->extension->getHookFile($extension, 'postuninstall')) include $postUninstallHook; - $this->display(); - } - - /** - * Activate an extension; - * - * @param string $extension - * @access public - * @return void - */ - public function activate($extension, $ignore = 'no') - { - if($ignore == 'no') - { - $return = $this->extension->checkFile($extension); - if($return->result != 'ok') - { - $ignoreLink = inlink('activate', "extension=$extension&ignore=yes"); - $resetLink = inlink('browse', 'type=deactivated'); - $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $ignoreLink, $resetLink); - die($this->display()); - } - } - - $this->extension->copyPackageFiles($extension); - $this->extension->updateExtension($extension, array('status' => 'installed')); - $this->view->header->title = $this->lang->extension->activateFinished; - $this->display(); - } - - /** - * Deactivate an extension - * - * @param string $extension - * @access public - * @return void - */ - public function deactivate($extension) - { - $this->extension->updateExtension($extension, array('status' => 'deactivated')); - $this->view->removeCommands = $this->extension->removePackage($extension); - $this->view->header->title = $this->lang->extension->deactivateFinished; - $this->display(); - } - - /** - * Upload an extension - * - * @param string $type - * @access public - * @return void - */ - public function upload($type = 'install') - { - if($_FILES) - { - $tmpName = $_FILES['file']['tmp_name']; - $fileName = $_FILES['file']['name']; - $extension = basename($fileName, '.zip'); - move_uploaded_file($tmpName, $this->app->getTmpRoot() . "/extension/$fileName"); - $param = $type == 'install' ? "extension=$extension" : "extension=$extension&downLink=&md5=&type=&overridePackage=no&ignoreCompatible=yes&overrideFile=no&agreeLicense=no&upgrade=1"; - $this->locate(inlink('install', $param)); - } - $this->display(); - } - - /** - * Erase an extension. - * - * @param string $extension - * @access public - * @return void - */ - public function erase($extension) - { - $this->view->removeCommands = $this->extension->erasePackage($extension); - $this->view->header->title = $this->lang->extension->eraseFinished; - $this->display(); - } - - /** - * Update extension. - * - * @param string $extension - * @param string $downLink - * @param string $md5 - * @param string $type - * @access public - * @return void - */ - public function upgrade($extension, $downLink, $md5, $type) - { - $this->extension->removePackage($extension); - $this->locate(inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=no&ignoreCompatible=yes&overrideFile=no&agreeLicense=no&upgrade=1")); - } - - /** - * Browse the structure of extension. - * - * @param int $extension - * @access public - * @return void - */ - public function structure($extension) - { - $this->view->extension = $this->extension->getInfoFromDB($extension); - $this->display(); - } -} + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +class extension extends control +{ + /** + * Browse extensions. + * + * @param string $status + * @access public + * @return void + */ + public function browse($status = 'installed') + { + $extensions = $this->extension->getLocalExtensions($status); + $versions = array(); + if($extensions and $status == 'installed') + { + /* Get latest release from remote. */ + $extCodes = helper::safe64Encode(join(',', array_keys($extensions))); + $results = $this->extension->getExtensionsByAPI('bycode', $extCodes, $recTotal = 0, $recPerPage = 1000, $pageID = 1); + if(isset($results->extensions)) + { + $remoteReleases = $results->extensions; + foreach($remoteReleases as $release) + { + if(!isset($extensions[$release->code])) continue; + + $extension = $extensions[$release->code]; + $extension->viewLink = $release->viewLink; + if($extension->version != $release->latestRelease->releaseVersion and $this->extension->checkVersion($release->latestRelease->zentaoVersion)) + { + $extension->upgradeLink = ($release->latestRelease->charge or !$release->latestRelease->public) ? $release->latestRelease->downLink : inlink('upgrade', "extension=$release->code&downLink=" . helper::safe64Encode($release->latestRelease->downLink) . "&md5={$release->latestRelease->md5}&type=$release->type"); + } + } + } + } + + $this->view->header->title = $this->lang->extension->browse; + $this->view->position[] = $this->lang->extension->browse; + $this->view->tab = $status; + $this->view->extensions = $extensions; + $this->view->versions = $versions; + $this->display(); + } + + /** + * Obtain extensions from the community. + * + * @param string $type + * @param string $param + * @access public + * @return void + */ + public function obtain($type = 'byUpdatedTime', $param = '', $recTotal = 0, $recPerPage = 10, $pageID = 1) + { + /* Init vars. */ + $type = strtolower($type); + $moduleID = $type == 'bymodule' ? (int)$param : 0; + $extensions = array(); + $pager = null; + + /* Set the key. */ + if($type == 'bysearch') $param = helper::safe64Encode($this->post->key); + + /* Get results from the api. */ + $results = $this->extension->getExtensionsByAPI($type, $param, $recTotal, $recPerPage, $pageID); + if($results) + { + $this->app->loadClass('pager', $static = true); + $pager = new pager($results->dbPager->recTotal, $results->dbPager->recPerPage, $results->dbPager->pageID); + $extensions = $results->extensions; + } + + $this->view->moduleTree = $this->extension->getModulesByAPI(); + $this->view->extensions = $extensions; + $this->view->installeds = $this->extension->getLocalExtensions('installed'); + $this->view->pager = $pager; + $this->view->tab = 'obtain'; + $this->view->type = $type; + $this->view->moduleID = $moduleID; + $this->display(); + } + + /** + * Install a extension + * + * @param string $extension + * @param string $downLink + * @param string $md5 + * @param string $type + * @param string $overridePackage + * @param string $ignoreCompatible + * @param string $overrideFile + * @param string $agreeLicense + * @param int $upgrade + * @access public + * @return void + */ + public function install($extension, $downLink = '', $md5 = '', $type = '', $overridePackage = 'no', $ignoreCompatible = 'no', $overrideFile = 'no', $agreeLicense = 'no', $upgrade = 0) + { + $this->view->error = ''; + $this->view->header->title = $this->lang->extension->install . $this->lang->colon . $extension; + + /* Get the package file name. */ + $packageFile = $this->extension->getPackageFile($extension); + + if($downLink) + { + /* Checking download path. */ + $return = $this->extension->checkDownloadPath(); + if($return->result != 'ok') + { + $this->view->error = $return->error; + die($this->display()); + } + + /* Check file exists or not. */ + if(file_exists($packageFile) and $overridePackage == 'no') + { + $overrideLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=yes&ignoreCompatible=$ignoreCompatible&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); + $this->view->error = sprintf($this->lang->extension->errorPackageFileExists, $packageFile, $overrideLink); + die($this->display()); + } + + /* Download the package file. */ + $this->extension->downloadPackage($extension, helper::safe64Decode($downLink)); + if(!file_exists($packageFile)) + { + $this->view->error = sprintf($this->lang->extension->errorDownloadFailed, $packageFile); + die($this->display()); + } + elseif($md5 != '' and md5_file($packageFile) != $md5) + { + unlink($packageFile); + $this->view->error = sprintf($this->lang->extension->errorMd5Checking, $packageFile); + die($this->display()); + } + } + + /* Check the package file exists or not. */ + if(!file_exists($packageFile)) + { + $this->view->error = sprintf($this->lang->extension->errorPackageNotFound, $packageFile); + die($this->display()); + } + + /* Checking the extension pathes. */ + $return = $this->extension->checkExtensionPathes($extension); + if($this->session->dirs2Created == false) $this->session->set('dirs2Created', $return->dirs2Created); // Save the dirs to be created. + if($return->result != 'ok') + { + $this->view->error = $return->errors; + die($this->display()); + } + + /* Extract the package. */ + $return = $this->extension->extractPackage($extension); + if($return->result != 'ok') + { + $this->view->error = sprintf($this->lang->extension->errorExtracted, $packageFile, $return->error); + die($this->display()); + } + + /* Check version comptiable. */ + $zentaoVersion = $this->extension->getZentaoVersion($extension); + if(!$this->extension->checkVersion($zentaoVersion) and $ignoreCompatible == 'no') + { + $ignoreLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=yes&overrideFile=$overrideFile&agreeLicense=$agreeLicense&upgrade=$upgrade"); + $returnLink = inlink('obtain'); + $this->view->error = sprintf($this->lang->extension->errorCheckIncompatible, $ignoreLink, $returnLink); + die($this->display()); + } + + /* Check files in the package conflicts with exists files or not. */ + if($overrideFile == 'no') + { + $return = $this->extension->checkFile($extension); + if($return->result != 'ok') + { + $overrideLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=yes&agreeLicense=$agreeLicense&upgrade=$upgrade"); + $returnLink = inlink('obtain'); + $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $overrideLink, $returnLink); + die($this->display()); + } + } + + /* Print the license form. */ + if($agreeLicense == 'no') + { + $extensionInfo = $this->extension->getInfoFromPackage($extension); + $license = $this->extension->processLicense($extensionInfo->license); + $agreeLink = inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=$overridePackage&ignoreCompatible=$ignoreCompatible&overrideFile=$overrideFile&agreeLicense=yes&upgrade=$upgrade"); + $this->view->license = $license; + $this->view->author = $extensionInfo->author; + $this->view->agreeLink = $agreeLink; + die($this->display()); + } + + if($upgrade) + { + $info = $this->extension->parseExtensionCFG($extension); + $this->post->upgradeVersion = isset($info->version) ? $info->version : ''; + $info = $this->extension->getInfoFromDB($extension); + $this->post->installedVersion = $info ? $info->version : ''; + } + + /* The preInstall hook file. */ + $hook = $upgrade ? 'preupgrade' : 'preinstall'; + if($preHookFile = $this->extension->getHookFile($extension, $hook)) include $preHookFile; + + /* Save to database. */ + $this->extension->saveExtension($extension, $type); + + /* Copy files to target directory. */ + $this->view->files = $this->extension->copyPackageFiles($extension); + + /* Judge need execute db install or not. */ + $data->status = 'installed'; + $data->dirs = $this->session->dirs2Created; + $data->files = $this->view->files; + $data->installedTime = helper::now(); + $this->session->set('dirs2Created', array()); // clean the session. + + /* Execute the install.sql. */ + if($this->extension->needExecuteDB($extension, 'install')) + { + $return = $this->extension->executeDB($extension, 'install'); + if($return->result != 'ok') + { + $this->view->error = sprintf($this->lang->extension->errorInstallDB, $return->error); + die($this->display()); + } + } + + /* Update status, dirs, files and installed time. */ + $this->extension->updateExtension($extension, $data); + $this->view->downloadedPackage = !empty($downLink); + + /* The postInstall hook file. */ + $hook = $upgrade ? 'postupgrade' : 'postinstall'; + if($postHookFile = $this->extension->getHookFile($extension, $hook)) include $postHookFile; + + $this->display(); + } + + /** + * Uninstall an extension. + * + * @param string $extension + * @access public + * @return void + */ + public function uninstall($extension) + { + if($preUninstallHook = $this->extension->getHookFile($extension, 'preuninstall')) include $preUninstallHook; + + $this->extension->executeDB($extension, 'uninstall'); + $this->extension->updateExtension($extension, array('status' => 'available')); + $this->view->removeCommands = $this->extension->removePackage($extension); + $this->view->header->title = $this->lang->extension->uninstallFinished; + + if($postUninstallHook = $this->extension->getHookFile($extension, 'postuninstall')) include $postUninstallHook; + $this->display(); + } + + /** + * Activate an extension; + * + * @param string $extension + * @access public + * @return void + */ + public function activate($extension, $ignore = 'no') + { + if($ignore == 'no') + { + $return = $this->extension->checkFile($extension); + if($return->result != 'ok') + { + $ignoreLink = inlink('activate', "extension=$extension&ignore=yes"); + $resetLink = inlink('browse', 'type=deactivated'); + $this->view->error = sprintf($this->lang->extension->errorFileConflicted, $return->error, $ignoreLink, $resetLink); + die($this->display()); + } + } + + $this->extension->copyPackageFiles($extension); + $this->extension->updateExtension($extension, array('status' => 'installed')); + $this->view->header->title = $this->lang->extension->activateFinished; + $this->display(); + } + + /** + * Deactivate an extension + * + * @param string $extension + * @access public + * @return void + */ + public function deactivate($extension) + { + $this->extension->updateExtension($extension, array('status' => 'deactivated')); + $this->view->removeCommands = $this->extension->removePackage($extension); + $this->view->header->title = $this->lang->extension->deactivateFinished; + $this->display(); + } + + /** + * Upload an extension + * + * @param string $type + * @access public + * @return void + */ + public function upload($type = 'install') + { + if($_FILES) + { + $tmpName = $_FILES['file']['tmp_name']; + $fileName = $_FILES['file']['name']; + $extension = basename($fileName, '.zip'); + move_uploaded_file($tmpName, $this->app->getTmpRoot() . "/extension/$fileName"); + $param = $type == 'install' ? "extension=$extension" : "extension=$extension&downLink=&md5=&type=&overridePackage=no&ignoreCompatible=yes&overrideFile=no&agreeLicense=no&upgrade=1"; + $this->locate(inlink('install', $param)); + } + $this->display(); + } + + /** + * Erase an extension. + * + * @param string $extension + * @access public + * @return void + */ + public function erase($extension) + { + $this->view->removeCommands = $this->extension->erasePackage($extension); + $this->view->header->title = $this->lang->extension->eraseFinished; + $this->display(); + } + + /** + * Update extension. + * + * @param string $extension + * @param string $downLink + * @param string $md5 + * @param string $type + * @access public + * @return void + */ + public function upgrade($extension, $downLink, $md5, $type) + { + $this->extension->removePackage($extension); + $this->locate(inlink('install', "extension=$extension&downLink=$downLink&md5=$md5&type=$type&overridePackage=no&ignoreCompatible=yes&overrideFile=no&agreeLicense=no&upgrade=1")); + } + + /** + * Browse the structure of extension. + * + * @param int $extension + * @access public + * @return void + */ + public function structure($extension) + { + $this->view->extension = $this->extension->getInfoFromDB($extension); + $this->display(); + } +} diff --git a/module/extension/lang/en.php b/module/extension/lang/en.php index 6a64f8db2e..472c7ffabd 100644 --- a/module/extension/lang/en.php +++ b/module/extension/lang/en.php @@ -1,95 +1,95 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->extension->common = 'Extension'; -$lang->extension->browse = 'Browse'; -$lang->extension->install = 'Install'; -$lang->extension->installAuto = 'AutoInstall'; -$lang->extension->installForce = 'ForceInstall'; -$lang->extension->uninstall = 'Uninstall'; -$lang->extension->activate = 'Activate'; -$lang->extension->deactivate = 'Deactivate'; -$lang->extension->obtain = 'Obtain'; -$lang->extension->view = 'Info'; -$lang->extension->download = 'Download'; -$lang->extension->downloadAB = 'Down'; -$lang->extension->upload = 'Upload and install'; -$lang->extension->uploadUpgrade = 'Upload and upgrade'; -$lang->extension->erase = 'Erase'; -$lang->extension->upgrade = 'Upgrade'; -$lang->extension->agreeLicense = 'I agree the license'; - -$lang->extension->structure = 'Structure'; -$lang->extension->installed = 'Installed'; -$lang->extension->deactivated = 'Deactivated'; -$lang->extension->available = 'Downloaded'; - -$lang->extension->id = 'ID'; -$lang->extension->name = 'Name'; -$lang->extension->code = 'Code'; -$lang->extension->version = 'Version'; -$lang->extension->compatible = 'Compatible'; -$lang->extension->latest = 'Latest:%s,need zentao %s'; -$lang->extension->author = 'Author'; -$lang->extension->license = 'License'; -$lang->extension->intro = 'Description'; -$lang->extension->abstract = 'Abstract'; -$lang->extension->site = 'Site'; -$lang->extension->addedTime = 'Added Time'; -$lang->extension->updatedTime = 'Updated Time'; -$lang->extension->downloads = 'Downloads'; -$lang->extension->public = 'Public'; -$lang->extension->compatible = 'Compatible'; -$lang->extension->grade = 'Grade'; - -$lang->extension->publicList[0] = 'Manually'; -$lang->extension->publicList[1] = 'Auto'; - -$lang->extension->compatibleList[0] = 'Unknow'; -$lang->extension->compatibleList[1] = 'Compatible'; - -$lang->extension->byDownloads = 'Downloads'; -$lang->extension->byAddedTime = 'New added'; -$lang->extension->byUpdatedTime = 'Last updated'; -$lang->extension->bySearch = 'Search'; -$lang->extension->byCategory = 'By Category'; - -$lang->extension->installFailed = 'Install failed, the reason is:'; -$lang->extension->installFinished = 'Good, the extension has been installed successfully.'; -$lang->extension->refreshPage = 'Refresh'; -$lang->extension->uninstallFinished = 'Extension has been successfully uninstalled.'; -$lang->extension->deactivateFinished = 'Extension has been successfully deactivated.'; -$lang->extension->activateFinished = 'Extension has been successfully activated.'; -$lang->extension->eraseFinished = 'Extension has been successfully erased.'; -$lang->extension->unremovedFiles = 'There are some unremoved files, you need remove them manually'; -$lang->extension->executeCommands = '

          Execute the following commands to fix them:

          '; -$lang->extension->successDownloadedPackage = 'Successfully downloaded the package file.'; -$lang->extension->successCopiedFiles = 'Successfully copied files. '; -$lang->extension->successInstallDB = 'Successfully installed database.'; -$lang->extension->viewInstalled = 'View installed extensions.'; -$lang->extension->viewAvailable = 'View available extensions'; -$lang->extension->viewDeactivated = 'View deactivated extensions'; - -$lang->extension->errorOccurs = 'Error:'; -$lang->extension->errorGetModules = "Get extensions' categories data from the www.zentao.net failed. "; -$lang->extension->errorGetExtensions = 'Get extensions from www.zentao.net failed. You can visit
          www.zentao.net to find your extensions, download it manually and then upload to zentaopms to install it.'; -$lang->extension->errorDownloadPathNotFound = 'The save path of package file %sdoes not exists.
          For linux users, can execute mkdir -p %s to fix it.'; -$lang->extension->errorDownloadPathNotWritable = 'The save path of package file %sis not writable.
          For linux users, can execute sudo chmod 777 %s to fix it.'; -$lang->extension->errorPackageFileExists = 'There is already a file with the same name %s.

          If you want to install again, please click this link.

          '; -$lang->extension->errorDownloadFailed = 'Download failed, please try again. Or you can download it manually and upload it to install.'; -$lang->extension->errorMd5Checking = 'The downloawd files checking failed, Please download it manually and upload it to install'; -$lang->extension->errorExtracted = 'The package file %s extracted failed. The error is:
          %s'; -$lang->extension->errorCheckIncompatible = 'This extenion is not compatible with current zentao version.

          You can force install or cancel the installation

          .'; -$lang->extension->errorFileConflicted = 'There are some files conflicted:
          %s

          You can Overide them or Cancel the installation

          .'; -$lang->extension->errorPackageNotFound = 'The package file %s not found, perhaps download failed, try again.'; -$lang->extension->errorTargetPathNotWritable = 'Target path %s not writable.'; -$lang->extension->errorTargetPathNotExists = 'Target path %s not exists'; -$lang->extension->errorInstallDB = 'Execute database sql failed, the error is: %s'; + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->extension->common = 'Extension'; +$lang->extension->browse = 'Browse'; +$lang->extension->install = 'Install'; +$lang->extension->installAuto = 'AutoInstall'; +$lang->extension->installForce = 'ForceInstall'; +$lang->extension->uninstall = 'Uninstall'; +$lang->extension->activate = 'Activate'; +$lang->extension->deactivate = 'Deactivate'; +$lang->extension->obtain = 'Obtain'; +$lang->extension->view = 'Info'; +$lang->extension->download = 'Download'; +$lang->extension->downloadAB = 'Down'; +$lang->extension->upload = 'Upload and install'; +$lang->extension->uploadUpgrade = 'Upload and upgrade'; +$lang->extension->erase = 'Erase'; +$lang->extension->upgrade = 'Upgrade'; +$lang->extension->agreeLicense = 'I agree the license'; + +$lang->extension->structure = 'Structure'; +$lang->extension->installed = 'Installed'; +$lang->extension->deactivated = 'Deactivated'; +$lang->extension->available = 'Downloaded'; + +$lang->extension->id = 'ID'; +$lang->extension->name = 'Name'; +$lang->extension->code = 'Code'; +$lang->extension->version = 'Version'; +$lang->extension->compatible = 'Compatible'; +$lang->extension->latest = 'Latest:%s,need zentao %s'; +$lang->extension->author = 'Author'; +$lang->extension->license = 'License'; +$lang->extension->intro = 'Description'; +$lang->extension->abstract = 'Abstract'; +$lang->extension->site = 'Site'; +$lang->extension->addedTime = 'Added Time'; +$lang->extension->updatedTime = 'Updated Time'; +$lang->extension->downloads = 'Downloads'; +$lang->extension->public = 'Public'; +$lang->extension->compatible = 'Compatible'; +$lang->extension->grade = 'Grade'; + +$lang->extension->publicList[0] = 'Manually'; +$lang->extension->publicList[1] = 'Auto'; + +$lang->extension->compatibleList[0] = 'Unknow'; +$lang->extension->compatibleList[1] = 'Compatible'; + +$lang->extension->byDownloads = 'Downloads'; +$lang->extension->byAddedTime = 'New added'; +$lang->extension->byUpdatedTime = 'Last updated'; +$lang->extension->bySearch = 'Search'; +$lang->extension->byCategory = 'By Category'; + +$lang->extension->installFailed = 'Install failed, the reason is:'; +$lang->extension->installFinished = 'Good, the extension has been installed successfully.'; +$lang->extension->refreshPage = 'Refresh'; +$lang->extension->uninstallFinished = 'Extension has been successfully uninstalled.'; +$lang->extension->deactivateFinished = 'Extension has been successfully deactivated.'; +$lang->extension->activateFinished = 'Extension has been successfully activated.'; +$lang->extension->eraseFinished = 'Extension has been successfully erased.'; +$lang->extension->unremovedFiles = 'There are some unremoved files, you need remove them manually'; +$lang->extension->executeCommands = '

          Execute the following commands to fix them:

          '; +$lang->extension->successDownloadedPackage = 'Successfully downloaded the package file.'; +$lang->extension->successCopiedFiles = 'Successfully copied files. '; +$lang->extension->successInstallDB = 'Successfully installed database.'; +$lang->extension->viewInstalled = 'View installed extensions.'; +$lang->extension->viewAvailable = 'View available extensions'; +$lang->extension->viewDeactivated = 'View deactivated extensions'; + +$lang->extension->errorOccurs = 'Error:'; +$lang->extension->errorGetModules = "Get extensions' categories data from the www.zentao.net failed. "; +$lang->extension->errorGetExtensions = 'Get extensions from www.zentao.net failed. You can visit
          www.zentao.net to find your extensions, download it manually and then upload to zentaopms to install it.'; +$lang->extension->errorDownloadPathNotFound = 'The save path of package file %sdoes not exists.
          For linux users, can execute mkdir -p %s to fix it.'; +$lang->extension->errorDownloadPathNotWritable = 'The save path of package file %sis not writable.
          For linux users, can execute sudo chmod 777 %s to fix it.'; +$lang->extension->errorPackageFileExists = 'There is already a file with the same name %s.

          If you want to install again, please click this link.

          '; +$lang->extension->errorDownloadFailed = 'Download failed, please try again. Or you can download it manually and upload it to install.'; +$lang->extension->errorMd5Checking = 'The downloawd files checking failed, Please download it manually and upload it to install'; +$lang->extension->errorExtracted = 'The package file %s extracted failed. The error is:
          %s'; +$lang->extension->errorCheckIncompatible = 'This extenion is not compatible with current zentao version.

          You can force install or cancel the installation

          .'; +$lang->extension->errorFileConflicted = 'There are some files conflicted:
          %s

          You can Overide them or Cancel the installation

          .'; +$lang->extension->errorPackageNotFound = 'The package file %s not found, perhaps download failed, try again.'; +$lang->extension->errorTargetPathNotWritable = 'Target path %s not writable.'; +$lang->extension->errorTargetPathNotExists = 'Target path %s not exists'; +$lang->extension->errorInstallDB = 'Execute database sql failed, the error is: %s'; diff --git a/module/extension/lang/zh-cn.php b/module/extension/lang/zh-cn.php index 6fc7d54708..72d1a0c737 100644 --- a/module/extension/lang/zh-cn.php +++ b/module/extension/lang/zh-cn.php @@ -1,95 +1,95 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->extension->common = '插件管理'; -$lang->extension->browse = '浏览插件'; -$lang->extension->install = '安装插件'; -$lang->extension->installAuto = '自动安装'; -$lang->extension->installForce = '强制安装'; -$lang->extension->uninstall = '卸载'; -$lang->extension->activate = '激活'; -$lang->extension->deactivate = '禁用'; -$lang->extension->obtain = '获得插件'; -$lang->extension->view = '详情'; -$lang->extension->download = '下载插件'; -$lang->extension->downloadAB = '下载'; -$lang->extension->upload = '本地安装'; -$lang->extension->uploadUpgrade = '本地升级'; -$lang->extension->erase = '清除'; -$lang->extension->upgrade = '升级'; -$lang->extension->agreeLicense = '我同意该授权'; - -$lang->extension->structure = '目录结构'; -$lang->extension->installed = '已安装'; -$lang->extension->deactivated = '被禁用'; -$lang->extension->available = '已下载'; - -$lang->extension->id = '编号'; -$lang->extension->name = '名称'; -$lang->extension->code = '插件代号'; -$lang->extension->version = '版本'; -$lang->extension->compatible = '适用版本'; -$lang->extension->latest = '最新版本%s,兼容禅道%s'; -$lang->extension->author = '作者'; -$lang->extension->license = '授权'; -$lang->extension->intro = '详情'; -$lang->extension->abstract = '简介'; -$lang->extension->site = '官网'; -$lang->extension->addedTime = '添加时间'; -$lang->extension->updatedTime = '更新时间'; -$lang->extension->downloads = '下载量'; -$lang->extension->public = '下载方式'; -$lang->extension->compatible = '兼容性'; -$lang->extension->grade = '评分'; - -$lang->extension->publicList[0] = '手工下载'; -$lang->extension->publicList[1] = '直接下载'; - -$lang->extension->compatibleList[0] = '未知'; -$lang->extension->compatibleList[1] = '兼容'; - -$lang->extension->byDownloads = '最多下载'; -$lang->extension->byAddedTime = '最新添加'; -$lang->extension->byUpdatedTime = '最近更新'; -$lang->extension->bySearch = '搜索'; -$lang->extension->byCategory = '分类浏览'; - -$lang->extension->installFailed = '安装失败,错误原因如下:'; -$lang->extension->installFinished = '恭喜您,插件顺利的安装成功!'; -$lang->extension->refreshPage = '刷新页面'; -$lang->extension->uninstallFinished = '插件已经成功卸载'; -$lang->extension->deactivateFinished = '插件已经成功禁用'; -$lang->extension->activateFinished = '插件已经成功激活'; -$lang->extension->eraseFinished = '插件已经成功清除'; -$lang->extension->unremovedFiles = '有一些文件或目录未能删除,需要手工删除'; -$lang->extension->executeCommands = '

          执行下面的命令来修正这些问题:

          '; -$lang->extension->successDownloadedPackage = '成功下载插件'; -$lang->extension->successCopiedFiles = '成功拷贝文件'; -$lang->extension->successInstallDB = '成功安装数据库'; -$lang->extension->viewInstalled = '查看已安装插件'; -$lang->extension->viewAvailable = '查看可安装插件'; -$lang->extension->viewDeactivated = '查看已禁用插件'; - -$lang->extension->errorOccurs = '错误:'; -$lang->extension->errorGetModules = '从www.zentao.net获得插件分类失败。可能是因为网络方面的原因,请检查后重新刷新页面。'; -$lang->extension->errorGetExtensions = '从www.zentao.net获得插件失败。可能是因为网络方面的原因,您可以到
          www.zentao.net手工下载插件,然后上传安装。'; -$lang->extension->errorDownloadPathNotFound = '插件下载存储路径%s不存在。
          linux下面请执行命令:mkdir -p %s来修正。'; -$lang->extension->errorDownloadPathNotWritable = '插件下载存储路径%s不可写。
          linux下面请执行命令:sudo chmod 777 %s来修正。'; -$lang->extension->errorPackageFileExists = '下载路径已经有一个名为的%s附件。

          重新安装,请点击此链接

          '; -$lang->extension->errorDownloadFailed = '下载失败,请重新下载。如果多次重试还不行,请尝试手工下载,然后通过上传功能上传。'; -$lang->extension->errorMd5Checking = '下载文件不完整,请重新下载。如果多次重试还不行,请尝试手工下载,然后通过上传功能上传。'; -$lang->extension->errorExtracted = '包文件 %s 解压缩失败,可能不是一个有效的zip文件。错误信息如下:
          %s'; -$lang->extension->errorCheckIncompatible = '该插件与禅道版本不兼容,安装后可能无法使用。。

          您可以选择 强制安装 或者 取消安装

          '; -$lang->extension->errorFileConflicted = '有以下安装文件冲突:
          %s

          您可以选择 覆盖安装 或者 取消安装

          '; -$lang->extension->errorPackageNotFound = '包文件 %s 没有找到,可能是因为自动下载失败。您可以尝试再次下载。'; -$lang->extension->errorTargetPathNotWritable = '目标路径 %s 不可写。'; -$lang->extension->errorTargetPathNotExists = '目标路径 %s 不存在。'; -$lang->extension->errorInstallDB = '执行数据库语句失败。错误信息如下:%s'; + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->extension->common = '插件管理'; +$lang->extension->browse = '浏览插件'; +$lang->extension->install = '安装插件'; +$lang->extension->installAuto = '自动安装'; +$lang->extension->installForce = '强制安装'; +$lang->extension->uninstall = '卸载'; +$lang->extension->activate = '激活'; +$lang->extension->deactivate = '禁用'; +$lang->extension->obtain = '获得插件'; +$lang->extension->view = '详情'; +$lang->extension->download = '下载插件'; +$lang->extension->downloadAB = '下载'; +$lang->extension->upload = '本地安装'; +$lang->extension->uploadUpgrade = '本地升级'; +$lang->extension->erase = '清除'; +$lang->extension->upgrade = '升级'; +$lang->extension->agreeLicense = '我同意该授权'; + +$lang->extension->structure = '目录结构'; +$lang->extension->installed = '已安装'; +$lang->extension->deactivated = '被禁用'; +$lang->extension->available = '已下载'; + +$lang->extension->id = '编号'; +$lang->extension->name = '名称'; +$lang->extension->code = '插件代号'; +$lang->extension->version = '版本'; +$lang->extension->compatible = '适用版本'; +$lang->extension->latest = '最新版本%s,兼容禅道%s'; +$lang->extension->author = '作者'; +$lang->extension->license = '授权'; +$lang->extension->intro = '详情'; +$lang->extension->abstract = '简介'; +$lang->extension->site = '官网'; +$lang->extension->addedTime = '添加时间'; +$lang->extension->updatedTime = '更新时间'; +$lang->extension->downloads = '下载量'; +$lang->extension->public = '下载方式'; +$lang->extension->compatible = '兼容性'; +$lang->extension->grade = '评分'; + +$lang->extension->publicList[0] = '手工下载'; +$lang->extension->publicList[1] = '直接下载'; + +$lang->extension->compatibleList[0] = '未知'; +$lang->extension->compatibleList[1] = '兼容'; + +$lang->extension->byDownloads = '最多下载'; +$lang->extension->byAddedTime = '最新添加'; +$lang->extension->byUpdatedTime = '最近更新'; +$lang->extension->bySearch = '搜索'; +$lang->extension->byCategory = '分类浏览'; + +$lang->extension->installFailed = '安装失败,错误原因如下:'; +$lang->extension->installFinished = '恭喜您,插件顺利的安装成功!'; +$lang->extension->refreshPage = '刷新页面'; +$lang->extension->uninstallFinished = '插件已经成功卸载'; +$lang->extension->deactivateFinished = '插件已经成功禁用'; +$lang->extension->activateFinished = '插件已经成功激活'; +$lang->extension->eraseFinished = '插件已经成功清除'; +$lang->extension->unremovedFiles = '有一些文件或目录未能删除,需要手工删除'; +$lang->extension->executeCommands = '

          执行下面的命令来修正这些问题:

          '; +$lang->extension->successDownloadedPackage = '成功下载插件'; +$lang->extension->successCopiedFiles = '成功拷贝文件'; +$lang->extension->successInstallDB = '成功安装数据库'; +$lang->extension->viewInstalled = '查看已安装插件'; +$lang->extension->viewAvailable = '查看可安装插件'; +$lang->extension->viewDeactivated = '查看已禁用插件'; + +$lang->extension->errorOccurs = '错误:'; +$lang->extension->errorGetModules = '从www.zentao.net获得插件分类失败。可能是因为网络方面的原因,请检查后重新刷新页面。'; +$lang->extension->errorGetExtensions = '从www.zentao.net获得插件失败。可能是因为网络方面的原因,您可以到
          www.zentao.net手工下载插件,然后上传安装。'; +$lang->extension->errorDownloadPathNotFound = '插件下载存储路径%s不存在。
          linux下面请执行命令:mkdir -p %s来修正。'; +$lang->extension->errorDownloadPathNotWritable = '插件下载存储路径%s不可写。
          linux下面请执行命令:sudo chmod 777 %s来修正。'; +$lang->extension->errorPackageFileExists = '下载路径已经有一个名为的%s附件。

          重新安装,请点击此链接

          '; +$lang->extension->errorDownloadFailed = '下载失败,请重新下载。如果多次重试还不行,请尝试手工下载,然后通过上传功能上传。'; +$lang->extension->errorMd5Checking = '下载文件不完整,请重新下载。如果多次重试还不行,请尝试手工下载,然后通过上传功能上传。'; +$lang->extension->errorExtracted = '包文件 %s 解压缩失败,可能不是一个有效的zip文件。错误信息如下:
          %s'; +$lang->extension->errorCheckIncompatible = '该插件与禅道版本不兼容,安装后可能无法使用。。

          您可以选择 强制安装 或者 取消安装

          '; +$lang->extension->errorFileConflicted = '有以下安装文件冲突:
          %s

          您可以选择 覆盖安装 或者 取消安装

          '; +$lang->extension->errorPackageNotFound = '包文件 %s 没有找到,可能是因为自动下载失败。您可以尝试再次下载。'; +$lang->extension->errorTargetPathNotWritable = '目标路径 %s 不可写。'; +$lang->extension->errorTargetPathNotExists = '目标路径 %s 不存在。'; +$lang->extension->errorInstallDB = '执行数据库语句失败。错误信息如下:%s'; diff --git a/module/extension/lang/zh-tw.php b/module/extension/lang/zh-tw.php index 600a698bd4..49f433b207 100644 --- a/module/extension/lang/zh-tw.php +++ b/module/extension/lang/zh-tw.php @@ -1,95 +1,95 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->extension->common = '插件管理'; -$lang->extension->browse = '瀏覽插件'; -$lang->extension->install = '安裝插件'; -$lang->extension->installAuto = '自動安裝'; -$lang->extension->installForce = '強制安裝'; -$lang->extension->uninstall = '卸載'; -$lang->extension->activate = '激活'; -$lang->extension->deactivate = '禁用'; -$lang->extension->obtain = '獲得插件'; -$lang->extension->view = '詳情'; -$lang->extension->download = '下載插件'; -$lang->extension->downloadAB = '下載'; -$lang->extension->upload = '本地安裝'; -$lang->extension->uploadUpgrade = '本地升級'; -$lang->extension->erase = '清除'; -$lang->extension->upgrade = '升級'; -$lang->extension->agreeLicense = '我同意該授權'; - -$lang->extension->structure = '目錄結構'; -$lang->extension->installed = '已安裝'; -$lang->extension->deactivated = '被禁用'; -$lang->extension->available = '已下載'; - -$lang->extension->id = '編號'; -$lang->extension->name = '名稱'; -$lang->extension->code = '插件代號'; -$lang->extension->version = '版本'; -$lang->extension->compatible = '適用版本'; -$lang->extension->latest = '最新版本%s,兼容禪道%s'; -$lang->extension->author = '作者'; -$lang->extension->license = '授權'; -$lang->extension->intro = '詳情'; -$lang->extension->abstract = '簡介'; -$lang->extension->site = '官網'; -$lang->extension->addedTime = '添加時間'; -$lang->extension->updatedTime = '更新時間'; -$lang->extension->downloads = '下載量'; -$lang->extension->public = '下載方式'; -$lang->extension->compatible = '兼容性'; -$lang->extension->grade = '評分'; - -$lang->extension->publicList[0] = '手工下載'; -$lang->extension->publicList[1] = '直接下載'; - -$lang->extension->compatibleList[0] = '未知'; -$lang->extension->compatibleList[1] = '兼容'; - -$lang->extension->byDownloads = '最多下載'; -$lang->extension->byAddedTime = '最新添加'; -$lang->extension->byUpdatedTime = '最近更新'; -$lang->extension->bySearch = '搜索'; -$lang->extension->byCategory = '分類瀏覽'; - -$lang->extension->installFailed = '安裝失敗,錯誤原因如下:'; -$lang->extension->installFinished = '恭喜您,插件順利的安裝成功!'; -$lang->extension->refreshPage = '刷新頁面'; -$lang->extension->uninstallFinished = '插件已經成功卸載'; -$lang->extension->deactivateFinished = '插件已經成功禁用'; -$lang->extension->activateFinished = '插件已經成功激活'; -$lang->extension->eraseFinished = '插件已經成功清除'; -$lang->extension->unremovedFiles = '有一些檔案或目錄未能刪除,需要手工刪除'; -$lang->extension->executeCommands = '

          執行下面的命令來修正這些問題:

          '; -$lang->extension->successDownloadedPackage = '成功下載插件'; -$lang->extension->successCopiedFiles = '成功拷貝檔案'; -$lang->extension->successInstallDB = '成功安裝資料庫'; -$lang->extension->viewInstalled = '查看已安裝插件'; -$lang->extension->viewAvailable = '查看可安裝插件'; -$lang->extension->viewDeactivated = '查看已禁用插件'; - -$lang->extension->errorOccurs = '錯誤:'; -$lang->extension->errorGetModules = '從www.zentao.net獲得插件分類失敗。可能是因為網絡方面的原因,請檢查後重新刷新頁面。'; -$lang->extension->errorGetExtensions = '從www.zentao.net獲得插件失敗。可能是因為網絡方面的原因,您可以到
          www.zentao.net手工下載插件,然後上傳安裝。'; -$lang->extension->errorDownloadPathNotFound = '插件下載存儲路徑%s不存在。
          linux下面請執行命令:mkdir -p %s來修正。'; -$lang->extension->errorDownloadPathNotWritable = '插件下載存儲路徑%s不可寫。
          linux下面請執行命令:sudo chmod 777 %s來修正。'; -$lang->extension->errorPackageFileExists = '下載路徑已經有一個名為的%s附件。

          重新安裝,請點擊此連結

          '; -$lang->extension->errorDownloadFailed = '下載失敗,請重新下載。如果多次重試還不行,請嘗試手工下載,然後通過上傳功能上傳。'; -$lang->extension->errorMd5Checking = '下載檔案不完整,請重新下載。如果多次重試還不行,請嘗試手工下載,然後通過上傳功能上傳。'; -$lang->extension->errorExtracted = '包檔案 %s 解壓縮失敗,可能不是一個有效的zip檔案。錯誤信息如下:
          %s'; -$lang->extension->errorCheckIncompatible = '該插件與禪道版本不兼容,安裝後可能無法使用。。

          您可以選擇 強制安裝 或者 取消安裝

          '; -$lang->extension->errorFileConflicted = '有以下安裝檔案衝突:
          %s

          您可以選擇 覆蓋安裝 或者 取消安裝

          '; -$lang->extension->errorPackageNotFound = '包檔案 %s 沒有找到,可能是因為自動下載失敗。您可以嘗試再次下載。'; -$lang->extension->errorTargetPathNotWritable = '目標路徑 %s 不可寫。'; -$lang->extension->errorTargetPathNotExists = '目標路徑 %s 不存在。'; -$lang->extension->errorInstallDB = '執行資料庫語句失敗。錯誤信息如下:%s'; + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->extension->common = '插件管理'; +$lang->extension->browse = '瀏覽插件'; +$lang->extension->install = '安裝插件'; +$lang->extension->installAuto = '自動安裝'; +$lang->extension->installForce = '強制安裝'; +$lang->extension->uninstall = '卸載'; +$lang->extension->activate = '激活'; +$lang->extension->deactivate = '禁用'; +$lang->extension->obtain = '獲得插件'; +$lang->extension->view = '詳情'; +$lang->extension->download = '下載插件'; +$lang->extension->downloadAB = '下載'; +$lang->extension->upload = '本地安裝'; +$lang->extension->uploadUpgrade = '本地升級'; +$lang->extension->erase = '清除'; +$lang->extension->upgrade = '升級'; +$lang->extension->agreeLicense = '我同意該授權'; + +$lang->extension->structure = '目錄結構'; +$lang->extension->installed = '已安裝'; +$lang->extension->deactivated = '被禁用'; +$lang->extension->available = '已下載'; + +$lang->extension->id = '編號'; +$lang->extension->name = '名稱'; +$lang->extension->code = '插件代號'; +$lang->extension->version = '版本'; +$lang->extension->compatible = '適用版本'; +$lang->extension->latest = '最新版本%s,兼容禪道%s'; +$lang->extension->author = '作者'; +$lang->extension->license = '授權'; +$lang->extension->intro = '詳情'; +$lang->extension->abstract = '簡介'; +$lang->extension->site = '官網'; +$lang->extension->addedTime = '添加時間'; +$lang->extension->updatedTime = '更新時間'; +$lang->extension->downloads = '下載量'; +$lang->extension->public = '下載方式'; +$lang->extension->compatible = '兼容性'; +$lang->extension->grade = '評分'; + +$lang->extension->publicList[0] = '手工下載'; +$lang->extension->publicList[1] = '直接下載'; + +$lang->extension->compatibleList[0] = '未知'; +$lang->extension->compatibleList[1] = '兼容'; + +$lang->extension->byDownloads = '最多下載'; +$lang->extension->byAddedTime = '最新添加'; +$lang->extension->byUpdatedTime = '最近更新'; +$lang->extension->bySearch = '搜索'; +$lang->extension->byCategory = '分類瀏覽'; + +$lang->extension->installFailed = '安裝失敗,錯誤原因如下:'; +$lang->extension->installFinished = '恭喜您,插件順利的安裝成功!'; +$lang->extension->refreshPage = '刷新頁面'; +$lang->extension->uninstallFinished = '插件已經成功卸載'; +$lang->extension->deactivateFinished = '插件已經成功禁用'; +$lang->extension->activateFinished = '插件已經成功激活'; +$lang->extension->eraseFinished = '插件已經成功清除'; +$lang->extension->unremovedFiles = '有一些檔案或目錄未能刪除,需要手工刪除'; +$lang->extension->executeCommands = '

          執行下面的命令來修正這些問題:

          '; +$lang->extension->successDownloadedPackage = '成功下載插件'; +$lang->extension->successCopiedFiles = '成功拷貝檔案'; +$lang->extension->successInstallDB = '成功安裝資料庫'; +$lang->extension->viewInstalled = '查看已安裝插件'; +$lang->extension->viewAvailable = '查看可安裝插件'; +$lang->extension->viewDeactivated = '查看已禁用插件'; + +$lang->extension->errorOccurs = '錯誤:'; +$lang->extension->errorGetModules = '從www.zentao.net獲得插件分類失敗。可能是因為網絡方面的原因,請檢查後重新刷新頁面。'; +$lang->extension->errorGetExtensions = '從www.zentao.net獲得插件失敗。可能是因為網絡方面的原因,您可以到
          www.zentao.net手工下載插件,然後上傳安裝。'; +$lang->extension->errorDownloadPathNotFound = '插件下載存儲路徑%s不存在。
          linux下面請執行命令:mkdir -p %s來修正。'; +$lang->extension->errorDownloadPathNotWritable = '插件下載存儲路徑%s不可寫。
          linux下面請執行命令:sudo chmod 777 %s來修正。'; +$lang->extension->errorPackageFileExists = '下載路徑已經有一個名為的%s附件。

          重新安裝,請點擊此連結

          '; +$lang->extension->errorDownloadFailed = '下載失敗,請重新下載。如果多次重試還不行,請嘗試手工下載,然後通過上傳功能上傳。'; +$lang->extension->errorMd5Checking = '下載檔案不完整,請重新下載。如果多次重試還不行,請嘗試手工下載,然後通過上傳功能上傳。'; +$lang->extension->errorExtracted = '包檔案 %s 解壓縮失敗,可能不是一個有效的zip檔案。錯誤信息如下:
          %s'; +$lang->extension->errorCheckIncompatible = '該插件與禪道版本不兼容,安裝後可能無法使用。。

          您可以選擇 強制安裝 或者 取消安裝

          '; +$lang->extension->errorFileConflicted = '有以下安裝檔案衝突:
          %s

          您可以選擇 覆蓋安裝 或者 取消安裝

          '; +$lang->extension->errorPackageNotFound = '包檔案 %s 沒有找到,可能是因為自動下載失敗。您可以嘗試再次下載。'; +$lang->extension->errorTargetPathNotWritable = '目標路徑 %s 不可寫。'; +$lang->extension->errorTargetPathNotExists = '目標路徑 %s 不存在。'; +$lang->extension->errorInstallDB = '執行資料庫語句失敗。錯誤信息如下:%s'; diff --git a/module/extension/model.php b/module/extension/model.php index 142477453f..c5a4645182 100644 --- a/module/extension/model.php +++ b/module/extension/model.php @@ -1,754 +1,754 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -class extensionModel extends model -{ - /** - * The extension manager version. Don't change it. - */ - const EXT_MANAGER_VERSION = '1.3'; - - /** - * The api agent(use snoopy). - * - * @var object - * @access public - */ - public $agent; - - /** - * The api root. - * - * @var string - * @access public - */ - public $apiRoot; - - /** - * The construct function. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->setAgent(); - $this->setApiRoot(); - $this->classFile = $this->app->loadClass('file'); - } - - /** - * Set the api agent. - * - * @access public - * @return void - */ - public function setAgent() - { - $this->agent = $this->app->loadClass('snoopy'); - } - - /** - * Set the apiRoot. - * - * @access public - * @return void - */ - public function setApiRoot() - { - $this->apiRoot = $this->config->extension->apiRoot; - } - - /** - * Fetch data from an api. - * - * @param string $url - * @access public - * @return mixed - */ - public function fetchAPI($url) - { - $url .= '?lang=' . str_replace('-', '_', $this->app->getClientLang()) . '&managerVersion=' . self::EXT_MANAGER_VERSION . '&zentaoVersion=' . $this->config->version; - $this->agent->fetch($url); - $result = json_decode($this->agent->results); - - if(!isset($result->status)) return false; - if($result->status != 'success') return false; - if(isset($result->data) and md5($result->data) != $result->md5) return false; - if(isset($result->data)) return json_decode($result->data); - } - - /** - * Get extension modules from the api. - * - * @access public - * @return string|bool - */ - public function getModulesByAPI() - { - $requestType = $this->config->requestType; - $webRoot = helper::safe64Encode($this->config->webRoot); - $apiURL = $this->apiRoot . 'apiGetmodules-' . $requestType . '-' . $webRoot . '.json'; - $data = $this->fetchAPI($apiURL); - if(isset($data->modules)) return $data->modules; - return false; - } - - /** - * Get extensions by some condition. - * - * @param string $type - * @param mixed $param - * @access public - * @return array|bool - */ - public function getExtensionsByAPI($type, $param, $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - $apiURL = $this->apiRoot . "apiGetExtensions-$type-$param-$recTotal-$recPerPage-$pageID.json"; - $data = $this->fetchAPI($apiURL); - if(isset($data->extensions)) - { - foreach($data->extensions as $extension) - { - $extension->currentRelease = isset($extension->compatibleRelease) ? $extension->compatibleRelease : $extension->latestRelease; - $extension->currentRelease->compatible = isset($extension->compatibleRelease); - } - return $data; - } - return false; - } - - /** - * Get versions for some extensions. - * - * @param string $extensions - * @access public - * @return array|bool - */ - public function getVersionsByAPI($extensions) - { - $extensions = helper::safe64Encode($extensions); - $apiURL = $this->apiRoot . 'apiGetVersions-' . $extensions . '.json'; - $data = $this->fetchAPI($apiURL); - if(isset($data->versions)) return (array)$data->versions; - return false; - } - - /** - * Download an extension. - * - * @param string $extension - * @param string $downLink - * @access public - * @return void - */ - public function downloadPackage($extension, $downLink) - { - $packageFile = $this->getPackageFile($extension); - $this->agent->fetch($downLink); - file_put_contents($packageFile, $this->agent->results); - } - - /** - * Get extensions by status. - * - * @param string $status - * @access public - * @return array - */ - public function getLocalExtensions($status) - { - $extensions = $this->dao->select('*')->from(TABLE_EXTENSION)->where('status')->eq($status)->fi()->fetchAll('code'); - foreach($extensions as $extension) - { - if($extension->site and stripos(strtolower($extension->site), 'http') === false) $extension->site = 'http://' . $extension->site; - } - return $extensions; - } - - /** - * Get extension info from database. - * - * @param string $extension - * @access public - * @return object - */ - public function getInfoFromDB($extension) - { - return $this->dao->select('*')->from(TABLE_EXTENSION)->where('code')->eq($extension)->fetch(); - } - - /** - * Get info of an extension from the package file. - * - * @param string $extension - * @access public - * @return object - */ - public function getInfoFromPackage($extension) - { - /* Init the data. */ - $data->name = $extension; - $data->code = $extension; - $data->version = 'unknown'; - $data->author = 'unknown'; - $data->desc = $extension; - $data->site = 'unknown'; - $data->license = 'unknown'; - $data->zentaoVersion = ''; - - $info = $this->parseExtensionCFG($extension); - foreach($info as $key => $value) if(isset($data->$key)) $data->$key = $value; - if(isset($info->zentaoversion)) $data->zentaoVersion = $info->zentaoversion; - - return $data; - } - - /** - * Parse extension's config file. - * - * @param string $extension - * @access public - * @return object - */ - public function parseExtensionCFG($extension) - { - $info = new stdclass(); - - /* First, try ini file. before 2.5 version. */ - $infoFile = "ext/$extension/doc/copyright.txt"; - if(file_exists($infoFile)) return (object)parse_ini_file($infoFile); - - /** - * Then try parse yaml file. since 2.5 version. - */ - - /* Try the yaml of current lang, then try en. */ - $lang = $this->app->getClientLang(); - $infoFile = "ext/$extension/doc/$lang.yaml"; - if(!file_exists($infoFile)) $infoFile = "ext/$extension/doc/en.yaml"; - if(!file_exists($infoFile)) return $info; - - /* Load the yaml file and parse it into object. */ - $this->app->loadClass('spyc', true); - $info = (object)spyc_load(file_get_contents($infoFile)); - if(isset($info->releases)) - { - krsort($info->releases); - $info->version = key($info->releases); - foreach($info->releases[$info->version] as $key => $value) $info->$key = $value; - } - return $info; - } - - /** - * Get the full path of the zip file of a extension. - * - * @param string $extension - * @access public - * @return string - */ - public function getPackageFile($extension) - { - return $this->app->getTmpRoot() . 'extension/' . $extension . '.zip'; - } - - /** - * Get pathes from an extension package. - * - * @param string $extension - * @access public - * @return array - */ - public function getPathesFromPackage($extension) - { - $pathes = array(); - $packageFile = $this->getPackageFile($extension); - - /* Get files from the package file. */ - $this->app->loadClass('pclzip', true); - $zip = new pclzip($packageFile); - $files = $zip->listContent(); - if($files) - { - foreach($files as $file) - { - $file = (object)$file; - if($file->folder) continue; - $file->filename = substr($file->filename, strpos($file->filename, '/') + 1); - $pathes[] = dirname($file->filename); - } - } - - /* Append the pathes to stored the extracted files. */ - $pathes[] = "module/extension/ext/"; - - return array_unique($pathes); - } - - /** - * Get all files from a package. - * - * @param string $extension - * @access public - * @return array - */ - public function getFilesFromPackage($extension) - { - $extensionDir = "ext/$extension/"; - $files = $this->classFile->readDir($extensionDir, array('db', 'doc')); - return $files; - } - - /** - * Get the extension's zentaoVersion - * - * @param string $extenstion - * @access public - * @return string - */ - public function getZentaoVersion($extension) - { - $info = $this->parseExtensionCFG($extension); - if(isset($info->zentaoVersion)) return $info->zentaoVersion; - if(isset($info->zentaoversion)) return $info->zentaoversion; - - return ''; - } - - /** - * Process license. If is opensource return the full text of it. - * - * @param string $license - * @access public - * @return string - */ - public function processLicense($license) - { - if(strlen($license) > 10) return $license; // more then 10 letters, not gpl, lgpl, apache, bsd or mit. - - $licenseFile = dirname(__FILE__) . '/license/' . strtolower($license) . '.txt'; - if(file_exists($licenseFile)) return file_get_contents($licenseFile); - - return $license; - } - - /** - * Get hook file for install or uninstall. - * - * @param string $extension - * @param string $hook preinstall|postinstall|preuninstall|postuninstall - * @access public - * @return string|bool - */ - public function getHookFile($extension, $hook) - { - $hookFile = "ext/$extension/hook/$hook.php"; - if(file_exists($hookFile)) return $hookFile; - return false; - } - - /** - * Get the install db file. - * - * @param string $extension - * @param string $method - * @access public - * @return string - */ - public function getDBFile($extension, $method = 'install') - { - return "ext/$extension/db/$method.sql"; - } - - /** - * Check the download path. - * - * @access public - * @return object the check result. - */ - public function checkDownloadPath() - { - /* Init the return. */ - $return->result = 'ok'; - $return->error = ''; - - $tmpRoot = $this->app->getTmpRoot(); - $downloadPath = $tmpRoot . 'extension'; - - if(!is_dir($downloadPath)) - { - if(is_writable($tmpRoot)) - { - mkdir($downloadPath); - } - else - { - $return->result = 'fail'; - $return->error = sprintf($this->lang->extension->errorDownloadPathNotFound, $downloadPath, $downloadPath); - } - } - elseif(!is_writable($downloadPath)) - { - $return->result = 'fail'; - $return->error = sprintf($this->lang->extension->errorDownloadPathNotWritable, $downloadPath, $downloadPath); - } - return $return; - } - - /** - * Check extension files. - * - * @param string $extension - * @access public - * @return object the check result. - */ - public function checkExtensionPathes($extension) - { - $return->result = 'ok'; - $return->errors = ''; - $return->mkdirCommands = ''; - $return->chmodCommands = ''; - $return->dirs2Created = array(); - - $appRoot = $this->app->getAppRoot(); - $pathes = $this->getPathesFromPackage($extension); - foreach($pathes as $path) - { - if($path == 'db' or $path == 'doc' or $path == 'hook') continue; - $path = $appRoot . $path; - if(is_dir($path)) - { - if(!is_writable($path)) - { - $return->errors .= sprintf($this->lang->extension->errorTargetPathNotWritable, $path) . '
          '; - $return->chmodCommands .= "sudo chmod -R 777 $path
          "; - } - } - else - { - if(!@mkdir($path, 0755, true)) - { - $return->errors .= sprintf($this->lang->extension->errorTargetPathNotExists, $path) . '
          '; - $return->mkdirCommands .= "mkdir -p $path
          "; - $return->chmodCommands .= "sudo chmod -R 777 $path
          "; - } - $return->dirs2Created[] = $path; - } - } - - if($return->errors) $return->result = 'fail'; - $return->mkdirCommands = str_replace('/', DIRECTORY_SEPARATOR, $return->mkdirCommands); - $return->errors .= $this->lang->extension->executeCommands . $return->mkdirCommands; - if(PHP_OS == 'Linux') $return->errors .= $return->chmodCommands; - return $return; - } - - /** - * Check the extension's version is compatibility for zentao version - * - * @param string $version - * @access public - * @return bool - */ - public function checkVersion($version) - { - if($version == 'all') return true; - $version = explode(',', $version); - if(in_array($this->config->version, $version)) return true; - return false; - } - - /** - * Check files in the package conflicts with exists files or not. - * - * @param string $extension - * @param string $type - * @param bool $isCheck - * @access public - * @return object - */ - public function checkFile($extension) - { - $return->result = 'ok'; - $return->error = ''; - - $extensionFiles = $this->getFilesFromPackage($extension); - $appRoot = $this->app->getAppRoot(); - foreach($extensionFiles as $extensionFile) - { - $compareFile = $appRoot . str_replace(realpath("ext/$extension") . '/', '', $extensionFile); - if(!file_exists($compareFile)) continue; - if(md5_file($extensionFile) != md5_file($compareFile)) $return->error .= $compareFile . '
          '; - } - - if($return->error != '') $return->result = 'fail'; - return $return; - } - - /** - * Extract an extension. - * - * @param string $extension - * @access public - * @return object - */ - public function extractPackage($extension) - { - $return->result = 'ok'; - $return->error = ''; - - /* try remove pre extracted files. */ - $extensionPath = "ext/$extension"; - if(is_dir($extensionPath)) $this->classFile->removeDir($extensionPath); - - /* Extract files. */ - $packageFile = $this->getPackageFile($extension); - $this->app->loadClass('pclzip', true); - $zip = new pclzip($packageFile); - $files = $zip->listContent(); - $removePath = $files[0]['filename']; - if($zip->extract(PCLZIP_OPT_PATH, $extensionPath, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0) - { - $return->result = 'fail'; - $return->error = $zip->errorInfo(true); - } - - return $return; - } - - /** - * Copy package files. - * - * @param int $extension - * @access public - * @return array - */ - public function copyPackageFiles($extension) - { - $appRoot = $this->app->getAppRoot(); - $extensionDir = "ext/$extension/"; - $pathes = scandir($extensionDir); - $copiedFiles = array(); - - foreach($pathes as $path) - { - if($path == 'db' or $path == 'doc' or $path == 'hook' or $path == '..' or $path == '.') continue; - $copiedFiles = $this->classFile->copyDir($extensionDir . $path, $appRoot . $path); - } - foreach($copiedFiles as $key => $copiedFile) - { - $copiedFiles[$copiedFile] = md5_file($copiedFile); - unset($copiedFiles[$key]); - } - return $copiedFiles; - } - - /** - * Remove an extension. - * - * @param string $extension - * @access public - * @return array the remove commands need executed manually. - */ - public function removePackage($extension) - { - $extension = $this->getInfoFromDB($extension); - $dirs = json_decode($extension->dirs); - $files = json_decode($extension->files); - $appRoot = $this->app->getAppRoot(); - $removeCommands = array(); - - /* Remove files first. */ - if($files) - { - foreach($files as $file => $savedMD5) - { - $file = $appRoot . $file; - if(!file_exists($file)) continue; - - if(md5_file($file) != $savedMD5) - { - $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $file #changed" : "del $file :changed"; - } - elseif(!@unlink($file)) - { - $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $file" : "del $file"; - } - } - } - - /* Then remove dirs. */ - if($dirs) - { - rsort($dirs); // remove from the lower level directory. - foreach($dirs as $dir) - { - if(!@rmdir($appRoot . $dir)) $removeCommands[] = "rmdir $appRoot$dir"; - } - } - - /* Clean model cache files. */ - $this->cleanModelCache(); - - return $removeCommands; - } - - /** - * Clean model cache files. - * - * @access public - * @return void - */ - public function cleanModelCache() - { - $modelCacheFiles = glob($this->app->getTmpRoot() . 'model/*'); - foreach($modelCacheFiles as $cacheFile) @unlink($cacheFile); - } - - /** - * Erase an extension's package file. - * - * @param string $extension - * @access public - * @return array the remove commands need executed manually. - */ - public function erasePackage($extension) - { - $removeCommands = array(); - - $this->dao->delete()->from(TABLE_EXTENSION)->where('code')->eq($extension)->exec(); - - /* Remove the zip file. */ - $packageFile = $this->getPackageFile($extension); - if(file_exists($packageFile) and !@unlink($packageFile)) - { - $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $packageFile" : "del $packageFile"; - } - - /* Remove the extracted files. */ - $extractedDir = realpath("ext/$extension"); - if($extractedDir != '/' and !$this->classFile->removeDir($extractedDir)) - { - $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $extractedDir" : "rmdir $extractedDir /s"; - } - - return $removeCommands; - } - - /** - * Judge need execute db install or not. - * - * @param string $extension - * @param string $method - * @access public - * @return bool - */ - public function needExecuteDB($extension, $method = 'install') - { - return file_exists($this->getDBFile($extension, $method)); - } - - /** - * Install the db. - * - * @param int $extension - * @access public - * @return object - */ - public function executeDB($extension, $method = 'install') - { - $return->result = 'ok'; - $return->error = ''; - - $dbFile = $this->getDBFile($extension, $method); - if(!file_exists($dbFile)) return $return; - - $sqls = file_get_contents($this->getDBFile($extension, $method)); - $sqls = explode(';', $sqls); - - foreach($sqls as $sql) - { - $sql = trim($sql); - if(empty($sql)) continue; - $sql = str_replace('zt_', $this->config->db->prefix, $sql); - - try - { - $this->dbh->query($sql); - } - catch (PDOException $e) - { - $return->error .= '

          ' . $e->getMessage() . "
          THE SQL IS: $sql

          "; - } - } - if($return->error) $return->result = 'fail'; - return $return; - } - - /** - * Save the extension to database. - * - * @param string $extension the extension code - * @param string $type the extension type - * @access public - * @return void - */ - public function saveExtension($extension, $type) - { - $code = $extension; - $extension = $this->getInfoFromPackage($extension); - $extension->status = 'available'; - $extension->code = $code; - $extension->type = $type; - $this->dao->replace(TABLE_EXTENSION)->data($extension)->exec(); - } - - /** - * Update an extension. - * - * @param string $extension - * @param string $status - * @param array $files - * @access public - * @return void - */ - public function updateExtension($extension, $data) - { - $data = (object)$data; - $appRoot = $this->app->getAppRoot(); - - if(isset($data->dirs)) - { - if($data->dirs) - { - foreach($data->dirs as $key => $dir) - { - $data->dirs[$key] = str_replace($appRoot, '', $dir); - } - } - $data->dirs = json_encode($data->dirs); - } - - if(isset($data->files)) - { - foreach($data->files as $fullFilePath => $md5) - { - $relativeFilePath = str_replace($appRoot, '', $fullFilePath); - $data->files[$relativeFilePath] = $md5; - unset($data->files[$fullFilePath]); - } - $data->files = json_encode($data->files); - } - return $this->dao->update(TABLE_EXTENSION)->data($data)->where('code')->eq($extension)->exec(); - } -} + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +class extensionModel extends model +{ + /** + * The extension manager version. Don't change it. + */ + const EXT_MANAGER_VERSION = '1.3'; + + /** + * The api agent(use snoopy). + * + * @var object + * @access public + */ + public $agent; + + /** + * The api root. + * + * @var string + * @access public + */ + public $apiRoot; + + /** + * The construct function. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->setAgent(); + $this->setApiRoot(); + $this->classFile = $this->app->loadClass('file'); + } + + /** + * Set the api agent. + * + * @access public + * @return void + */ + public function setAgent() + { + $this->agent = $this->app->loadClass('snoopy'); + } + + /** + * Set the apiRoot. + * + * @access public + * @return void + */ + public function setApiRoot() + { + $this->apiRoot = $this->config->extension->apiRoot; + } + + /** + * Fetch data from an api. + * + * @param string $url + * @access public + * @return mixed + */ + public function fetchAPI($url) + { + $url .= '?lang=' . str_replace('-', '_', $this->app->getClientLang()) . '&managerVersion=' . self::EXT_MANAGER_VERSION . '&zentaoVersion=' . $this->config->version; + $this->agent->fetch($url); + $result = json_decode($this->agent->results); + + if(!isset($result->status)) return false; + if($result->status != 'success') return false; + if(isset($result->data) and md5($result->data) != $result->md5) return false; + if(isset($result->data)) return json_decode($result->data); + } + + /** + * Get extension modules from the api. + * + * @access public + * @return string|bool + */ + public function getModulesByAPI() + { + $requestType = $this->config->requestType; + $webRoot = helper::safe64Encode($this->config->webRoot); + $apiURL = $this->apiRoot . 'apiGetmodules-' . $requestType . '-' . $webRoot . '.json'; + $data = $this->fetchAPI($apiURL); + if(isset($data->modules)) return $data->modules; + return false; + } + + /** + * Get extensions by some condition. + * + * @param string $type + * @param mixed $param + * @access public + * @return array|bool + */ + public function getExtensionsByAPI($type, $param, $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $apiURL = $this->apiRoot . "apiGetExtensions-$type-$param-$recTotal-$recPerPage-$pageID.json"; + $data = $this->fetchAPI($apiURL); + if(isset($data->extensions)) + { + foreach($data->extensions as $extension) + { + $extension->currentRelease = isset($extension->compatibleRelease) ? $extension->compatibleRelease : $extension->latestRelease; + $extension->currentRelease->compatible = isset($extension->compatibleRelease); + } + return $data; + } + return false; + } + + /** + * Get versions for some extensions. + * + * @param string $extensions + * @access public + * @return array|bool + */ + public function getVersionsByAPI($extensions) + { + $extensions = helper::safe64Encode($extensions); + $apiURL = $this->apiRoot . 'apiGetVersions-' . $extensions . '.json'; + $data = $this->fetchAPI($apiURL); + if(isset($data->versions)) return (array)$data->versions; + return false; + } + + /** + * Download an extension. + * + * @param string $extension + * @param string $downLink + * @access public + * @return void + */ + public function downloadPackage($extension, $downLink) + { + $packageFile = $this->getPackageFile($extension); + $this->agent->fetch($downLink); + file_put_contents($packageFile, $this->agent->results); + } + + /** + * Get extensions by status. + * + * @param string $status + * @access public + * @return array + */ + public function getLocalExtensions($status) + { + $extensions = $this->dao->select('*')->from(TABLE_EXTENSION)->where('status')->eq($status)->fi()->fetchAll('code'); + foreach($extensions as $extension) + { + if($extension->site and stripos(strtolower($extension->site), 'http') === false) $extension->site = 'http://' . $extension->site; + } + return $extensions; + } + + /** + * Get extension info from database. + * + * @param string $extension + * @access public + * @return object + */ + public function getInfoFromDB($extension) + { + return $this->dao->select('*')->from(TABLE_EXTENSION)->where('code')->eq($extension)->fetch(); + } + + /** + * Get info of an extension from the package file. + * + * @param string $extension + * @access public + * @return object + */ + public function getInfoFromPackage($extension) + { + /* Init the data. */ + $data->name = $extension; + $data->code = $extension; + $data->version = 'unknown'; + $data->author = 'unknown'; + $data->desc = $extension; + $data->site = 'unknown'; + $data->license = 'unknown'; + $data->zentaoVersion = ''; + + $info = $this->parseExtensionCFG($extension); + foreach($info as $key => $value) if(isset($data->$key)) $data->$key = $value; + if(isset($info->zentaoversion)) $data->zentaoVersion = $info->zentaoversion; + + return $data; + } + + /** + * Parse extension's config file. + * + * @param string $extension + * @access public + * @return object + */ + public function parseExtensionCFG($extension) + { + $info = new stdclass(); + + /* First, try ini file. before 2.5 version. */ + $infoFile = "ext/$extension/doc/copyright.txt"; + if(file_exists($infoFile)) return (object)parse_ini_file($infoFile); + + /** + * Then try parse yaml file. since 2.5 version. + */ + + /* Try the yaml of current lang, then try en. */ + $lang = $this->app->getClientLang(); + $infoFile = "ext/$extension/doc/$lang.yaml"; + if(!file_exists($infoFile)) $infoFile = "ext/$extension/doc/en.yaml"; + if(!file_exists($infoFile)) return $info; + + /* Load the yaml file and parse it into object. */ + $this->app->loadClass('spyc', true); + $info = (object)spyc_load(file_get_contents($infoFile)); + if(isset($info->releases)) + { + krsort($info->releases); + $info->version = key($info->releases); + foreach($info->releases[$info->version] as $key => $value) $info->$key = $value; + } + return $info; + } + + /** + * Get the full path of the zip file of a extension. + * + * @param string $extension + * @access public + * @return string + */ + public function getPackageFile($extension) + { + return $this->app->getTmpRoot() . 'extension/' . $extension . '.zip'; + } + + /** + * Get pathes from an extension package. + * + * @param string $extension + * @access public + * @return array + */ + public function getPathesFromPackage($extension) + { + $pathes = array(); + $packageFile = $this->getPackageFile($extension); + + /* Get files from the package file. */ + $this->app->loadClass('pclzip', true); + $zip = new pclzip($packageFile); + $files = $zip->listContent(); + if($files) + { + foreach($files as $file) + { + $file = (object)$file; + if($file->folder) continue; + $file->filename = substr($file->filename, strpos($file->filename, '/') + 1); + $pathes[] = dirname($file->filename); + } + } + + /* Append the pathes to stored the extracted files. */ + $pathes[] = "module/extension/ext/"; + + return array_unique($pathes); + } + + /** + * Get all files from a package. + * + * @param string $extension + * @access public + * @return array + */ + public function getFilesFromPackage($extension) + { + $extensionDir = "ext/$extension/"; + $files = $this->classFile->readDir($extensionDir, array('db', 'doc')); + return $files; + } + + /** + * Get the extension's zentaoVersion + * + * @param string $extenstion + * @access public + * @return string + */ + public function getZentaoVersion($extension) + { + $info = $this->parseExtensionCFG($extension); + if(isset($info->zentaoVersion)) return $info->zentaoVersion; + if(isset($info->zentaoversion)) return $info->zentaoversion; + + return ''; + } + + /** + * Process license. If is opensource return the full text of it. + * + * @param string $license + * @access public + * @return string + */ + public function processLicense($license) + { + if(strlen($license) > 10) return $license; // more then 10 letters, not gpl, lgpl, apache, bsd or mit. + + $licenseFile = dirname(__FILE__) . '/license/' . strtolower($license) . '.txt'; + if(file_exists($licenseFile)) return file_get_contents($licenseFile); + + return $license; + } + + /** + * Get hook file for install or uninstall. + * + * @param string $extension + * @param string $hook preinstall|postinstall|preuninstall|postuninstall + * @access public + * @return string|bool + */ + public function getHookFile($extension, $hook) + { + $hookFile = "ext/$extension/hook/$hook.php"; + if(file_exists($hookFile)) return $hookFile; + return false; + } + + /** + * Get the install db file. + * + * @param string $extension + * @param string $method + * @access public + * @return string + */ + public function getDBFile($extension, $method = 'install') + { + return "ext/$extension/db/$method.sql"; + } + + /** + * Check the download path. + * + * @access public + * @return object the check result. + */ + public function checkDownloadPath() + { + /* Init the return. */ + $return->result = 'ok'; + $return->error = ''; + + $tmpRoot = $this->app->getTmpRoot(); + $downloadPath = $tmpRoot . 'extension'; + + if(!is_dir($downloadPath)) + { + if(is_writable($tmpRoot)) + { + mkdir($downloadPath); + } + else + { + $return->result = 'fail'; + $return->error = sprintf($this->lang->extension->errorDownloadPathNotFound, $downloadPath, $downloadPath); + } + } + elseif(!is_writable($downloadPath)) + { + $return->result = 'fail'; + $return->error = sprintf($this->lang->extension->errorDownloadPathNotWritable, $downloadPath, $downloadPath); + } + return $return; + } + + /** + * Check extension files. + * + * @param string $extension + * @access public + * @return object the check result. + */ + public function checkExtensionPathes($extension) + { + $return->result = 'ok'; + $return->errors = ''; + $return->mkdirCommands = ''; + $return->chmodCommands = ''; + $return->dirs2Created = array(); + + $appRoot = $this->app->getAppRoot(); + $pathes = $this->getPathesFromPackage($extension); + foreach($pathes as $path) + { + if($path == 'db' or $path == 'doc' or $path == 'hook') continue; + $path = $appRoot . $path; + if(is_dir($path)) + { + if(!is_writable($path)) + { + $return->errors .= sprintf($this->lang->extension->errorTargetPathNotWritable, $path) . '
          '; + $return->chmodCommands .= "sudo chmod -R 777 $path
          "; + } + } + else + { + if(!@mkdir($path, 0755, true)) + { + $return->errors .= sprintf($this->lang->extension->errorTargetPathNotExists, $path) . '
          '; + $return->mkdirCommands .= "mkdir -p $path
          "; + $return->chmodCommands .= "sudo chmod -R 777 $path
          "; + } + $return->dirs2Created[] = $path; + } + } + + if($return->errors) $return->result = 'fail'; + $return->mkdirCommands = str_replace('/', DIRECTORY_SEPARATOR, $return->mkdirCommands); + $return->errors .= $this->lang->extension->executeCommands . $return->mkdirCommands; + if(PHP_OS == 'Linux') $return->errors .= $return->chmodCommands; + return $return; + } + + /** + * Check the extension's version is compatibility for zentao version + * + * @param string $version + * @access public + * @return bool + */ + public function checkVersion($version) + { + if($version == 'all') return true; + $version = explode(',', $version); + if(in_array($this->config->version, $version)) return true; + return false; + } + + /** + * Check files in the package conflicts with exists files or not. + * + * @param string $extension + * @param string $type + * @param bool $isCheck + * @access public + * @return object + */ + public function checkFile($extension) + { + $return->result = 'ok'; + $return->error = ''; + + $extensionFiles = $this->getFilesFromPackage($extension); + $appRoot = $this->app->getAppRoot(); + foreach($extensionFiles as $extensionFile) + { + $compareFile = $appRoot . str_replace(realpath("ext/$extension") . '/', '', $extensionFile); + if(!file_exists($compareFile)) continue; + if(md5_file($extensionFile) != md5_file($compareFile)) $return->error .= $compareFile . '
          '; + } + + if($return->error != '') $return->result = 'fail'; + return $return; + } + + /** + * Extract an extension. + * + * @param string $extension + * @access public + * @return object + */ + public function extractPackage($extension) + { + $return->result = 'ok'; + $return->error = ''; + + /* try remove pre extracted files. */ + $extensionPath = "ext/$extension"; + if(is_dir($extensionPath)) $this->classFile->removeDir($extensionPath); + + /* Extract files. */ + $packageFile = $this->getPackageFile($extension); + $this->app->loadClass('pclzip', true); + $zip = new pclzip($packageFile); + $files = $zip->listContent(); + $removePath = $files[0]['filename']; + if($zip->extract(PCLZIP_OPT_PATH, $extensionPath, PCLZIP_OPT_REMOVE_PATH, $removePath) == 0) + { + $return->result = 'fail'; + $return->error = $zip->errorInfo(true); + } + + return $return; + } + + /** + * Copy package files. + * + * @param int $extension + * @access public + * @return array + */ + public function copyPackageFiles($extension) + { + $appRoot = $this->app->getAppRoot(); + $extensionDir = "ext/$extension/"; + $pathes = scandir($extensionDir); + $copiedFiles = array(); + + foreach($pathes as $path) + { + if($path == 'db' or $path == 'doc' or $path == 'hook' or $path == '..' or $path == '.') continue; + $copiedFiles = $this->classFile->copyDir($extensionDir . $path, $appRoot . $path); + } + foreach($copiedFiles as $key => $copiedFile) + { + $copiedFiles[$copiedFile] = md5_file($copiedFile); + unset($copiedFiles[$key]); + } + return $copiedFiles; + } + + /** + * Remove an extension. + * + * @param string $extension + * @access public + * @return array the remove commands need executed manually. + */ + public function removePackage($extension) + { + $extension = $this->getInfoFromDB($extension); + $dirs = json_decode($extension->dirs); + $files = json_decode($extension->files); + $appRoot = $this->app->getAppRoot(); + $removeCommands = array(); + + /* Remove files first. */ + if($files) + { + foreach($files as $file => $savedMD5) + { + $file = $appRoot . $file; + if(!file_exists($file)) continue; + + if(md5_file($file) != $savedMD5) + { + $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $file #changed" : "del $file :changed"; + } + elseif(!@unlink($file)) + { + $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $file" : "del $file"; + } + } + } + + /* Then remove dirs. */ + if($dirs) + { + rsort($dirs); // remove from the lower level directory. + foreach($dirs as $dir) + { + if(!@rmdir($appRoot . $dir)) $removeCommands[] = "rmdir $appRoot$dir"; + } + } + + /* Clean model cache files. */ + $this->cleanModelCache(); + + return $removeCommands; + } + + /** + * Clean model cache files. + * + * @access public + * @return void + */ + public function cleanModelCache() + { + $modelCacheFiles = glob($this->app->getTmpRoot() . 'model/*'); + foreach($modelCacheFiles as $cacheFile) @unlink($cacheFile); + } + + /** + * Erase an extension's package file. + * + * @param string $extension + * @access public + * @return array the remove commands need executed manually. + */ + public function erasePackage($extension) + { + $removeCommands = array(); + + $this->dao->delete()->from(TABLE_EXTENSION)->where('code')->eq($extension)->exec(); + + /* Remove the zip file. */ + $packageFile = $this->getPackageFile($extension); + if(file_exists($packageFile) and !@unlink($packageFile)) + { + $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $packageFile" : "del $packageFile"; + } + + /* Remove the extracted files. */ + $extractedDir = realpath("ext/$extension"); + if($extractedDir != '/' and !$this->classFile->removeDir($extractedDir)) + { + $removeCommands[] = PHP_OS == 'Linux' ? "rm -fr $extractedDir" : "rmdir $extractedDir /s"; + } + + return $removeCommands; + } + + /** + * Judge need execute db install or not. + * + * @param string $extension + * @param string $method + * @access public + * @return bool + */ + public function needExecuteDB($extension, $method = 'install') + { + return file_exists($this->getDBFile($extension, $method)); + } + + /** + * Install the db. + * + * @param int $extension + * @access public + * @return object + */ + public function executeDB($extension, $method = 'install') + { + $return->result = 'ok'; + $return->error = ''; + + $dbFile = $this->getDBFile($extension, $method); + if(!file_exists($dbFile)) return $return; + + $sqls = file_get_contents($this->getDBFile($extension, $method)); + $sqls = explode(';', $sqls); + + foreach($sqls as $sql) + { + $sql = trim($sql); + if(empty($sql)) continue; + $sql = str_replace('zt_', $this->config->db->prefix, $sql); + + try + { + $this->dbh->query($sql); + } + catch (PDOException $e) + { + $return->error .= '

          ' . $e->getMessage() . "
          THE SQL IS: $sql

          "; + } + } + if($return->error) $return->result = 'fail'; + return $return; + } + + /** + * Save the extension to database. + * + * @param string $extension the extension code + * @param string $type the extension type + * @access public + * @return void + */ + public function saveExtension($extension, $type) + { + $code = $extension; + $extension = $this->getInfoFromPackage($extension); + $extension->status = 'available'; + $extension->code = $code; + $extension->type = $type; + $this->dao->replace(TABLE_EXTENSION)->data($extension)->exec(); + } + + /** + * Update an extension. + * + * @param string $extension + * @param string $status + * @param array $files + * @access public + * @return void + */ + public function updateExtension($extension, $data) + { + $data = (object)$data; + $appRoot = $this->app->getAppRoot(); + + if(isset($data->dirs)) + { + if($data->dirs) + { + foreach($data->dirs as $key => $dir) + { + $data->dirs[$key] = str_replace($appRoot, '', $dir); + } + } + $data->dirs = json_encode($data->dirs); + } + + if(isset($data->files)) + { + foreach($data->files as $fullFilePath => $md5) + { + $relativeFilePath = str_replace($appRoot, '', $fullFilePath); + $data->files[$relativeFilePath] = $md5; + unset($data->files[$fullFilePath]); + } + $data->files = json_encode($data->files); + } + return $this->dao->update(TABLE_EXTENSION)->data($data)->where('code')->eq($extension)->exec(); + } +} diff --git a/module/extension/view/activate.html.php b/module/extension/view/activate.html.php index cf765f2f0d..2e2335c3ba 100644 --- a/module/extension/view/activate.html.php +++ b/module/extension/view/activate.html.php @@ -1,33 +1,33 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - {$header->title}"; - echo "

          " . html::commonButton($lang->extension->viewInstalled, 'onclick=parent.location.href="' . inlink('browse', 'type=installed') . '"') . '

          '; - } - ?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + {$header->title}"; + echo "

          " . html::commonButton($lang->extension->viewInstalled, 'onclick=parent.location.href="' . inlink('browse', 'type=installed') . '"') . '

          '; + } + ?> +
          + + diff --git a/module/extension/view/browse.html.php b/module/extension/view/browse.html.php index 71516b9978..d383c9b4a7 100644 --- a/module/extension/view/browse.html.php +++ b/module/extension/view/browse.html.php @@ -1,61 +1,61 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - -
          name";?>
          -
          desc;?>
          -
          - extension->version}: {$extension->version} "; - echo "{$lang->extension->author}: {$extension->author} "; - ?> -
          -
          - code"), $lang->extension->structure, '', "class='button-c extension'"); - $deactivateCode = html::a(inlink('deactivate', "extension=$extension->code"), $lang->extension->deactivate, '', "class='button-c iframe'"); - $activateCode = html::a(inlink('activate', "extension=$extension->code"), $lang->extension->activate, '', "class='button-c iframe'"); - $uninstallCode = html::a(inlink('uninstall', "extension=$extension->code"), $lang->extension->uninstall, '', "class='button-c iframe'"); - $installCode = html::a(inlink('install', "extension=$extension->code"), $lang->extension->install, '', "class='button-c iframe'"); - $eraseCode = html::a(inlink('erase', "extension=$extension->code"), $lang->extension->erase, '', "class='button-c iframe'"); - - if(isset($extension->viewLink)) - { - echo html::a($extension->viewLink, $lang->extension->view, '', "class='button-c iframe'"); - } - if($extension->status == 'installed') - { - echo $structureCode; - } - if($extension->status == 'installed' and !empty($extension->upgradeLink)) - { - echo html::a($extension->upgradeLink, $lang->extension->upgrade, '', "class='button-c iframe'"); - } - - if($extension->type != 'patch') - { - if($extension->status == 'installed') echo $deactivateCode . $uninstallCode; - if($extension->status == 'deactivated') echo $activateCode . $uninstallCode; - if($extension->status == 'available') echo $installCode . $eraseCode; - } - echo html::a($extension->site, $lang->extension->site, '_blank', 'class=button-c'); - ?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + +
          name";?>
          +
          desc;?>
          +
          + extension->version}: {$extension->version} "; + echo "{$lang->extension->author}: {$extension->author} "; + ?> +
          +
          + code"), $lang->extension->structure, '', "class='button-c extension'"); + $deactivateCode = html::a(inlink('deactivate', "extension=$extension->code"), $lang->extension->deactivate, '', "class='button-c iframe'"); + $activateCode = html::a(inlink('activate', "extension=$extension->code"), $lang->extension->activate, '', "class='button-c iframe'"); + $uninstallCode = html::a(inlink('uninstall', "extension=$extension->code"), $lang->extension->uninstall, '', "class='button-c iframe'"); + $installCode = html::a(inlink('install', "extension=$extension->code"), $lang->extension->install, '', "class='button-c iframe'"); + $eraseCode = html::a(inlink('erase', "extension=$extension->code"), $lang->extension->erase, '', "class='button-c iframe'"); + + if(isset($extension->viewLink)) + { + echo html::a($extension->viewLink, $lang->extension->view, '', "class='button-c iframe'"); + } + if($extension->status == 'installed') + { + echo $structureCode; + } + if($extension->status == 'installed' and !empty($extension->upgradeLink)) + { + echo html::a($extension->upgradeLink, $lang->extension->upgrade, '', "class='button-c iframe'"); + } + + if($extension->type != 'patch') + { + if($extension->status == 'installed') echo $deactivateCode . $uninstallCode; + if($extension->status == 'deactivated') echo $activateCode . $uninstallCode; + if($extension->status == 'available') echo $installCode . $eraseCode; + } + echo html::a($extension->site, $lang->extension->site, '_blank', 'class=button-c'); + ?> +
          + + diff --git a/module/extension/view/checkscore.html.php b/module/extension/view/checkscore.html.php index 4e863989e2..aed10a40ec 100644 --- a/module/extension/view/checkscore.html.php +++ b/module/extension/view/checkscore.html.php @@ -1,28 +1,28 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - - {$lang->extension->needSorce}"; - echo "

          $error

          "; - ?> - -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + + {$lang->extension->needSorce}"; + echo "

          $error

          "; + ?> + +
          + + diff --git a/module/extension/view/deactivate.html.php b/module/extension/view/deactivate.html.php index d56306f89a..800fb2a4d8 100644 --- a/module/extension/view/deactivate.html.php +++ b/module/extension/view/deactivate.html.php @@ -1,31 +1,31 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - {$header->title}"; - if($removeCommands) - { - echo "

          {$lang->extension->unremovedFiles}

          "; - echo join($removeCommands, '
          '); - } - echo "

          " . html::commonButton($lang->extension->viewDeactivated, 'onclick=parent.location.href="' . inlink('browse', 'type=deactivated') . '"') . '

          '; - ?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + {$header->title}"; + if($removeCommands) + { + echo "

          {$lang->extension->unremovedFiles}

          "; + echo join($removeCommands, '
          '); + } + echo "

          " . html::commonButton($lang->extension->viewDeactivated, 'onclick=parent.location.href="' . inlink('browse', 'type=deactivated') . '"') . '

          '; + ?> +
          + + diff --git a/module/extension/view/erase.html.php b/module/extension/view/erase.html.php index 58978f7183..91994e1766 100644 --- a/module/extension/view/erase.html.php +++ b/module/extension/view/erase.html.php @@ -1,31 +1,31 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - {$header->title}"; - if($removeCommands) - { - echo "

          {$lang->extension->unremovedFiles}

          "; - echo join($removeCommands, '
          '); - } - echo "

          " . html::commonButton($lang->extension->viewAvailable, 'onclick=parent.location.href="' . inlink('browse', 'type=available') . '"') . '

          '; - ?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + {$header->title}"; + if($removeCommands) + { + echo "

          {$lang->extension->unremovedFiles}

          "; + echo join($removeCommands, '
          '); + } + echo "

          " . html::commonButton($lang->extension->viewAvailable, 'onclick=parent.location.href="' . inlink('browse', 'type=available') . '"') . '

          '; + ?> +
          + + diff --git a/module/extension/view/install.html.php b/module/extension/view/install.html.php index c29314438c..26f5ceed32 100644 --- a/module/extension/view/install.html.php +++ b/module/extension/view/install.html.php @@ -1,49 +1,49 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - - {$lang->extension->installFailed}"; - echo "

          $error

          "; - echo html::commonButton($lang->extension->refreshPage, 'onclick=location.href=location.href'); - ?> - - {$lang->extension->license}"; - echo html::textarea('license', $license) . '
          '; - echo '

          ' . html::a($agreeLink, $lang->extension->agreeLicense) . '

          '; - ?> - - {$lang->extension->successDownloadedPackage}"; - echo "

          {$lang->extension->successCopiedFiles}

          "; - echo '
            '; - foreach($files as $fileName => $md5) - { - echo "
          • $fileName
          • "; - } - echo '
          '; - echo "

          {$lang->extension->successInstallDB}

          "; - echo "

          {$lang->extension->installFinished}

          "; - echo "

          " . html::commonButton($lang->extension->viewInstalled, 'onclick=parent.location.href="' . inlink('browse') . '"') . '

          '; - ?> - -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + + {$lang->extension->installFailed}"; + echo "

          $error

          "; + echo html::commonButton($lang->extension->refreshPage, 'onclick=location.href=location.href'); + ?> + + {$lang->extension->license}"; + echo html::textarea('license', $license) . '
          '; + echo '

          ' . html::a($agreeLink, $lang->extension->agreeLicense) . '

          '; + ?> + + {$lang->extension->successDownloadedPackage}"; + echo "

          {$lang->extension->successCopiedFiles}

          "; + echo '
            '; + foreach($files as $fileName => $md5) + { + echo "
          • $fileName
          • "; + } + echo '
          '; + echo "

          {$lang->extension->successInstallDB}

          "; + echo "

          {$lang->extension->installFinished}

          "; + echo "

          " . html::commonButton($lang->extension->viewInstalled, 'onclick=parent.location.href="' . inlink('browse') . '"') . '

          '; + ?> + +
          + + diff --git a/module/extension/view/obtain.html.php b/module/extension/view/obtain.html.php index 1fca0f9619..9cdad31e88 100644 --- a/module/extension/view/obtain.html.php +++ b/module/extension/view/obtain.html.php @@ -1,113 +1,113 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - -
          -
          extension->obtain;?>
          -
          - " . html::a(inlink('obtain', 'type=byUpdatedTime'), $lang->extension->byUpdatedTime) . '
          '; - echo "" . html::a(inlink('obtain', 'type=byAddedTime'), $lang->extension->byAddedTime) . '
          '; - echo "" . html::a(inlink('obtain', 'type=byDownloads'), $lang->extension->byDownloads) . '
          '; - ?> -
          -
          extension->bySearch;?>
          -
          -
          '> - post->key, "class='text-1'") . html::submitButton($lang->extension->bySearch);?> -
          -
          -
          extension->byCategory;?>
          -
          - extension->errorGetModules);?> -
          -
          - - - currentRelease; - $latestRelease = $extension->latestRelease; - ?> - - - - - -
          -
          name . "($currentRelease->releaseVersion)";?>
          -
          - releaseVersion != $currentRelease->releaseVersion) - { - printf($lang->extension->latest, $latestRelease->viewLink, $latestRelease->releaseVersion, $latestRelease->zentaoVersion); - }?> -
          -
          -
          abstract;?>
          -
          - extension->author}: {$extension->author} "; - echo "{$lang->extension->downloads}: {$extension->downloads} "; - echo "{$lang->extension->compatible}: {$lang->extension->compatibleList[$currentRelease->compatible]} "; - echo "{$lang->extension->grade}: ", html::printStars($extension->stars); - ?> -
          -
          - code&downLink=" . helper::safe64Encode($currentRelease->downLink) . "&md5={$currentRelease->md5}&type=$extension->type&&overridePackage=no&ignoreCompitable=yes"); - echo html::a($extension->viewLink, $lang->extension->view, '', 'class="button-c extension"'); - if($currentRelease->public) - { - if($extension->type != 'computer' and $extension->type != 'mobile') - { - if(isset($installeds[$extension->code])) - { - if($installeds[$extension->code]->version != $extension->latestRelease->releaseVersion) - { - $upgradeLink = inlink('upgrade', "extension=$extension->code&downLink=" . helper::safe64Encode($currentRelease->downLink) . "&md5=$currentRelease->md5&type=$extension->type"); - echo html::a($upgradeLink, $lang->extension->upgrade, '', 'class="iframe button-c"'); - } - else - { - echo html::commonButton($lang->extension->installed, "disabled='disabled' style='color:gray'"); - } - } - else - { - $label = $currentRelease->compatible ? $lang->extension->installAuto : $lang->extension->installForce; - echo html::a($installLink, $label, '', 'class="iframe button-c"'); - } - } - } - echo html::a($currentRelease->downLink, $lang->extension->downloadAB, '', 'class="manual button-c"'); - echo html::a($extension->site, $lang->extension->site, '_blank', 'class=button-c'); - ?> -
          - - show();?> - -
          extension->errorOccurs;?>
          -
          extension->errorGetExtensions;?>
          - -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + +
          +
          extension->obtain;?>
          +
          + " . html::a(inlink('obtain', 'type=byUpdatedTime'), $lang->extension->byUpdatedTime) . '
          '; + echo "" . html::a(inlink('obtain', 'type=byAddedTime'), $lang->extension->byAddedTime) . '
          '; + echo "" . html::a(inlink('obtain', 'type=byDownloads'), $lang->extension->byDownloads) . '
          '; + ?> +
          +
          extension->bySearch;?>
          +
          +
          '> + post->key, "class='text-1'") . html::submitButton($lang->extension->bySearch);?> +
          +
          +
          extension->byCategory;?>
          +
          + extension->errorGetModules);?> +
          +
          + + + currentRelease; + $latestRelease = $extension->latestRelease; + ?> + + + + + +
          +
          name . "($currentRelease->releaseVersion)";?>
          +
          + releaseVersion != $currentRelease->releaseVersion) + { + printf($lang->extension->latest, $latestRelease->viewLink, $latestRelease->releaseVersion, $latestRelease->zentaoVersion); + }?> +
          +
          +
          abstract;?>
          +
          + extension->author}: {$extension->author} "; + echo "{$lang->extension->downloads}: {$extension->downloads} "; + echo "{$lang->extension->compatible}: {$lang->extension->compatibleList[$currentRelease->compatible]} "; + echo "{$lang->extension->grade}: ", html::printStars($extension->stars); + ?> +
          +
          + code&downLink=" . helper::safe64Encode($currentRelease->downLink) . "&md5={$currentRelease->md5}&type=$extension->type&&overridePackage=no&ignoreCompitable=yes"); + echo html::a($extension->viewLink, $lang->extension->view, '', 'class="button-c extension"'); + if($currentRelease->public) + { + if($extension->type != 'computer' and $extension->type != 'mobile') + { + if(isset($installeds[$extension->code])) + { + if($installeds[$extension->code]->version != $extension->latestRelease->releaseVersion) + { + $upgradeLink = inlink('upgrade', "extension=$extension->code&downLink=" . helper::safe64Encode($currentRelease->downLink) . "&md5=$currentRelease->md5&type=$extension->type"); + echo html::a($upgradeLink, $lang->extension->upgrade, '', 'class="iframe button-c"'); + } + else + { + echo html::commonButton($lang->extension->installed, "disabled='disabled' style='color:gray'"); + } + } + else + { + $label = $currentRelease->compatible ? $lang->extension->installAuto : $lang->extension->installForce; + echo html::a($installLink, $label, '', 'class="iframe button-c"'); + } + } + } + echo html::a($currentRelease->downLink, $lang->extension->downloadAB, '', 'class="manual button-c"'); + echo html::a($extension->site, $lang->extension->site, '_blank', 'class=button-c'); + ?> +
          + + show();?> + +
          extension->errorOccurs;?>
          +
          extension->errorGetExtensions;?>
          + +
          + + diff --git a/module/extension/view/structure.html.php b/module/extension/view/structure.html.php index 308a2382c1..c0fdcf230f 100644 --- a/module/extension/view/structure.html.php +++ b/module/extension/view/structure.html.php @@ -1,26 +1,26 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          name . '[' . $extension->code . '] ' .$lang->extension->structure . ':';?> -
          - app->getAppRoot(); - $files = json_decode($extension->files); - foreach($files as $file => $md5) echo $appRoot . $file . "
          "; - ?> -
          - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          name . '[' . $extension->code . '] ' .$lang->extension->structure . ':';?> +
          + app->getAppRoot(); + $files = json_decode($extension->files); + foreach($files as $file => $md5) echo $appRoot . $file . "
          "; + ?> +
          + diff --git a/module/extension/view/uninstall.html.php b/module/extension/view/uninstall.html.php index e6952fdb07..e8eff9d9d6 100644 --- a/module/extension/view/uninstall.html.php +++ b/module/extension/view/uninstall.html.php @@ -1,31 +1,31 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - {$header->title}"; - if($removeCommands) - { - echo "

          {$lang->extension->unremovedFiles}

          "; - echo join($removeCommands, '
          '); - } - echo "

          " . html::commonButton($lang->extension->viewAvailable, 'onclick=parent.location.href="' . inlink('browse', 'type=available') . '"') . '

          '; - ?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + {$header->title}"; + if($removeCommands) + { + echo "

          {$lang->extension->unremovedFiles}

          "; + echo join($removeCommands, '
          '); + } + echo "

          " . html::commonButton($lang->extension->viewAvailable, 'onclick=parent.location.href="' . inlink('browse', 'type=available') . '"') . '

          '; + ?> +
          + + diff --git a/module/extension/view/upload.html.php b/module/extension/view/upload.html.php index c5d937755f..56eb4470d8 100644 --- a/module/extension/view/upload.html.php +++ b/module/extension/view/upload.html.php @@ -1,19 +1,19 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - extension->install);?> -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + extension->install);?> +
          + + diff --git a/module/extension/view/waring.htm.php b/module/extension/view/waring.htm.php index 00c2c98eea..866107d546 100644 --- a/module/extension/view/waring.htm.php +++ b/module/extension/view/waring.htm.php @@ -1,29 +1,29 @@ - - * @package extension - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          title;?>
          - - {$lang->extension->waringInstall}"; - echo "

          $error

          "; - echo html::commonButton($lang->extension->refreshPage, 'onclick=location.href=location.href'); - ?> - -
          - - + + * @package extension + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          title;?>
          + + {$lang->extension->waringInstall}"; + echo "

          $error

          "; + echo html::commonButton($lang->extension->refreshPage, 'onclick=location.href=location.href'); + ?> + +
          + + diff --git a/module/file/control.php b/module/file/control.php index 375164803b..6cb59888ac 100644 --- a/module/file/control.php +++ b/module/file/control.php @@ -1,266 +1,266 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -class file extends control -{ - /** - * Build the upload form. - * - * @param int $fileCount - * @param float $percent - * @access public - * @return void - */ - public function buildForm($fileCount = 2, $percent = 0.9) - { - if(!file_exists($this->file->savePath)) - { - printf($this->lang->file->errorNotExists, $this->file->savePath); - return false; - } - elseif(!is_writable($this->file->savePath)) - { - printf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath); - return false; - } - $this->view->fileCount = $fileCount; - $this->view->percent = $percent; - $this->display(); - } - - /** - * AJAX: get upload request from the web editor. - * - * @access public - * @return void - */ - public function ajaxUpload() - { - $file = $this->file->getUpload('imgFile'); - $file = $file[0]; - if($file) - { - if(@move_uploaded_file($file['tmpname'], $this->file->savePath . $file['pathname'])) - { - $url = $this->file->webPath . $file['pathname']; - - $file['addedBy'] = $this->app->user->account; - $file['addedDate'] = helper::today(); - unset($file['tmpname']); - $this->dao->insert(TABLE_FILE)->data($file)->exec(); - - die(json_encode(array('error' => 0, 'url' => $url))); - } - else - { - $error = strip_tags(sprintf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath)); - die(json_encode(array('error' => 1, 'message' => $error))); - } - } - } - - /** - * Down a file. - * - * @param int $fileID - * @param string $mouse - * @access public - * @return void - */ - public function download($fileID, $mouse = '') - { - $file = $this->file->getById($fileID); - - /* Judge the mode, down or open. */ - $mode = 'down'; - $fileTypes = 'txt|jpg|jpeg|gif|png|bmp|xml|html'; - if(stripos($fileTypes, $file->extension) !== false and $mouse == 'left') $mode = 'open'; - - /* If the mode is open, locate directly. */ - if($mode == 'open') - { - if(file_exists($file->realPath))$this->locate($file->webPath); - $this->app->error("The file you visit $fileID not found.", __FILE__, __LINE__, true); - } - else - { - /* Down the file. */ - if(file_exists($file->realPath)) - { - $fileName = $file->title . '.' . $file->extension; - $fileData = file_get_contents($file->realPath); - $this->sendDownHeader($fileName, $file->extension, $fileData); - } - else - { - $this->app->error("The file you visit $fileID not found.", __FILE__, __LINE__, true); - } - } - } - - /** - * Export as csv format. - * - * @access public - * @return void - */ - public function export2CSV() - { - $this->view->fields = $this->post->fields; - $this->view->rows = $this->post->rows; - $output = $this->parse('file', 'export2csv'); - - /* If the language is zh-cn, convert to gbk. */ - $clientLang = $this->app->getClientLang(); - if($clientLang == 'zh-cn') - { - if(function_exists('mb_convert_encoding')) - { - $output = @mb_convert_encoding($output, 'gbk', 'utf-8'); - } - elseif(function_exists('iconv')) - { - $output = @iconv('utf-8', 'gbk', $output); - } - } - - $this->sendDownHeader($this->post->fileName, 'csv', $output); - } - - /** - * export as xml format - * - * @access public - * @return void - */ - public function export2XML() - { - $this->view->fields = $this->post->fields; - $this->view->rows = $this->post->rows; - - $output = $this->parse('file', 'export2XML'); - - $this->sendDownHeader($this->post->fileName, 'xml', $output); - } - - /** - * export as html format - * - * @access public - * @return void - */ - public function export2HTML() - { - $this->view->fields = $this->post->fields; - $this->view->rows = $this->post->rows; - $this->view->fileName = $this->post->fileName; - $output = $this->parse('file', 'export2Html'); - - $this->sendDownHeader($this->post->fileName, 'html', $output); - } - - /** - * Send the download header to the client. - * - * @param string $fileName - * @param string $extension - * @access public - * @return void - */ - public function sendDownHeader($fileName, $fileType, $content) - { - /* Set the downloading cookie, thus the export form page can use it to judge whether to close the window or not. */ - setcookie('downloading', 1); - - /* Append the extension name auto. */ - $extension = '.' . $fileType; - if(strpos($fileName, $extension) === false) $fileName .= $extension; - - /* urlencode the filename for ie. */ - if(strpos($this->server->http_user_agent, 'MSIE') !== false) $fileName = urlencode($fileName); - - /* Judge the content type. */ - $mimes = $this->config->file->mimes; - $contentType = isset($mimes[$fileType]) ? $mimes[$fileType] : $mimes['default']; - - header("Content-type: $contentType"); - header("Content-Disposition: attachment; filename=\"$fileName\""); - header("Pragma: no-cache"); - header("Expires: 0"); - die($content); - } - - /** - * Delete a file. - * - * @param int $fileID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($fileID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->file->confirmDelete, inlink('delete', "fileID=$fileID&confirm=yes"))); - } - else - { - $file = $this->file->getById($fileID); - $this->dao->delete()->from(TABLE_FILE)->where('id')->eq($fileID)->exec(); - $this->loadModel('action')->create($file->objectType, $file->objectID, 'deletedFile', '', $extra=$file->title); - @unlink($file->realPath); - die(js::reload('parent')); - } - } - - /** - * Print files. - * - * @param array $files - * @param string $fieldset - * @access public - * @return void - */ - public function printFiles($files, $fieldset) - { - $this->view->files = $files; - $this->view->fieldset = $fieldset; - $this->display(); - } - - /** - * Edit file's name. - * - * @param int $fileID - * @access public - * @return void - */ - public function edit($fileID) - { - if($_POST) - { - $this->app->loadLang('action'); - $file = $this->file->getByID($fileID); - $this->dao->update(TABLE_FILE)->set('title')->eq($this->post->fileName)->where('id')->eq($fileID)->exec(); - - $extension = "." . $file->extension; - $actionID = $this->loadModel('action')->create($file->objectType, $file->objectID, 'editfile', '', $this->post->fileName . $extension); - $changes[] = array('field' => 'fileName', 'old' => $file->title . $extension, 'new' => $this->post->fileName . $extension); - $this->action->logHistory($actionID, $changes); - - die(js::reload('parent.parent')); - } - - $this->view->file = $this->file->getById($fileID); - $this->display(); - } -} + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +class file extends control +{ + /** + * Build the upload form. + * + * @param int $fileCount + * @param float $percent + * @access public + * @return void + */ + public function buildForm($fileCount = 2, $percent = 0.9) + { + if(!file_exists($this->file->savePath)) + { + printf($this->lang->file->errorNotExists, $this->file->savePath); + return false; + } + elseif(!is_writable($this->file->savePath)) + { + printf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath); + return false; + } + $this->view->fileCount = $fileCount; + $this->view->percent = $percent; + $this->display(); + } + + /** + * AJAX: get upload request from the web editor. + * + * @access public + * @return void + */ + public function ajaxUpload() + { + $file = $this->file->getUpload('imgFile'); + $file = $file[0]; + if($file) + { + if(@move_uploaded_file($file['tmpname'], $this->file->savePath . $file['pathname'])) + { + $url = $this->file->webPath . $file['pathname']; + + $file['addedBy'] = $this->app->user->account; + $file['addedDate'] = helper::today(); + unset($file['tmpname']); + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + + die(json_encode(array('error' => 0, 'url' => $url))); + } + else + { + $error = strip_tags(sprintf($this->lang->file->errorCanNotWrite, $this->file->savePath, $this->file->savePath)); + die(json_encode(array('error' => 1, 'message' => $error))); + } + } + } + + /** + * Down a file. + * + * @param int $fileID + * @param string $mouse + * @access public + * @return void + */ + public function download($fileID, $mouse = '') + { + $file = $this->file->getById($fileID); + + /* Judge the mode, down or open. */ + $mode = 'down'; + $fileTypes = 'txt|jpg|jpeg|gif|png|bmp|xml|html'; + if(stripos($fileTypes, $file->extension) !== false and $mouse == 'left') $mode = 'open'; + + /* If the mode is open, locate directly. */ + if($mode == 'open') + { + if(file_exists($file->realPath))$this->locate($file->webPath); + $this->app->error("The file you visit $fileID not found.", __FILE__, __LINE__, true); + } + else + { + /* Down the file. */ + if(file_exists($file->realPath)) + { + $fileName = $file->title . '.' . $file->extension; + $fileData = file_get_contents($file->realPath); + $this->sendDownHeader($fileName, $file->extension, $fileData); + } + else + { + $this->app->error("The file you visit $fileID not found.", __FILE__, __LINE__, true); + } + } + } + + /** + * Export as csv format. + * + * @access public + * @return void + */ + public function export2CSV() + { + $this->view->fields = $this->post->fields; + $this->view->rows = $this->post->rows; + $output = $this->parse('file', 'export2csv'); + + /* If the language is zh-cn, convert to gbk. */ + $clientLang = $this->app->getClientLang(); + if($clientLang == 'zh-cn') + { + if(function_exists('mb_convert_encoding')) + { + $output = @mb_convert_encoding($output, 'gbk', 'utf-8'); + } + elseif(function_exists('iconv')) + { + $output = @iconv('utf-8', 'gbk', $output); + } + } + + $this->sendDownHeader($this->post->fileName, 'csv', $output); + } + + /** + * export as xml format + * + * @access public + * @return void + */ + public function export2XML() + { + $this->view->fields = $this->post->fields; + $this->view->rows = $this->post->rows; + + $output = $this->parse('file', 'export2XML'); + + $this->sendDownHeader($this->post->fileName, 'xml', $output); + } + + /** + * export as html format + * + * @access public + * @return void + */ + public function export2HTML() + { + $this->view->fields = $this->post->fields; + $this->view->rows = $this->post->rows; + $this->view->fileName = $this->post->fileName; + $output = $this->parse('file', 'export2Html'); + + $this->sendDownHeader($this->post->fileName, 'html', $output); + } + + /** + * Send the download header to the client. + * + * @param string $fileName + * @param string $extension + * @access public + * @return void + */ + public function sendDownHeader($fileName, $fileType, $content) + { + /* Set the downloading cookie, thus the export form page can use it to judge whether to close the window or not. */ + setcookie('downloading', 1); + + /* Append the extension name auto. */ + $extension = '.' . $fileType; + if(strpos($fileName, $extension) === false) $fileName .= $extension; + + /* urlencode the filename for ie. */ + if(strpos($this->server->http_user_agent, 'MSIE') !== false) $fileName = urlencode($fileName); + + /* Judge the content type. */ + $mimes = $this->config->file->mimes; + $contentType = isset($mimes[$fileType]) ? $mimes[$fileType] : $mimes['default']; + + header("Content-type: $contentType"); + header("Content-Disposition: attachment; filename=\"$fileName\""); + header("Pragma: no-cache"); + header("Expires: 0"); + die($content); + } + + /** + * Delete a file. + * + * @param int $fileID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($fileID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->file->confirmDelete, inlink('delete', "fileID=$fileID&confirm=yes"))); + } + else + { + $file = $this->file->getById($fileID); + $this->dao->delete()->from(TABLE_FILE)->where('id')->eq($fileID)->exec(); + $this->loadModel('action')->create($file->objectType, $file->objectID, 'deletedFile', '', $extra=$file->title); + @unlink($file->realPath); + die(js::reload('parent')); + } + } + + /** + * Print files. + * + * @param array $files + * @param string $fieldset + * @access public + * @return void + */ + public function printFiles($files, $fieldset) + { + $this->view->files = $files; + $this->view->fieldset = $fieldset; + $this->display(); + } + + /** + * Edit file's name. + * + * @param int $fileID + * @access public + * @return void + */ + public function edit($fileID) + { + if($_POST) + { + $this->app->loadLang('action'); + $file = $this->file->getByID($fileID); + $this->dao->update(TABLE_FILE)->set('title')->eq($this->post->fileName)->where('id')->eq($fileID)->exec(); + + $extension = "." . $file->extension; + $actionID = $this->loadModel('action')->create($file->objectType, $file->objectID, 'editfile', '', $this->post->fileName . $extension); + $changes[] = array('field' => 'fileName', 'old' => $file->title . $extension, 'new' => $this->post->fileName . $extension); + $this->action->logHistory($actionID, $changes); + + die(js::reload('parent.parent')); + } + + $this->view->file = $this->file->getById($fileID); + $this->display(); + } +} diff --git a/module/file/lang/en.php b/module/file/lang/en.php index a67e7218df..02ad006c14 100644 --- a/module/file/lang/en.php +++ b/module/file/lang/en.php @@ -1,23 +1,23 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->file->common = 'File'; -$lang->file->download = 'Download'; -$lang->file->edit = 'Edit file name'; -$lang->file->inputFileName = 'Input file name'; -$lang->file->delete = 'Delete'; -$lang->file->export2CSV = 'Export CSV'; -$lang->file->ajaxUpload = 'AJAX: upload file from editor'; -$lang->file->label = 'Title: '; - -$lang->file->errorNotExists = "The directory '%s' is no exist"; -$lang->file->errorCanNotWrite = "The directory '%s' is unwritable, please change it's permission. Command in linux:sudo -R chmod 777 '%s'"; -$lang->file->confirmDelete = " Are you sure to delete this file?"; + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->file->common = 'File'; +$lang->file->download = 'Download'; +$lang->file->edit = 'Edit file name'; +$lang->file->inputFileName = 'Input file name'; +$lang->file->delete = 'Delete'; +$lang->file->export2CSV = 'Export CSV'; +$lang->file->ajaxUpload = 'AJAX: upload file from editor'; +$lang->file->label = 'Title: '; + +$lang->file->errorNotExists = "The directory '%s' is no exist"; +$lang->file->errorCanNotWrite = "The directory '%s' is unwritable, please change it's permission. Command in linux:sudo -R chmod 777 '%s'"; +$lang->file->confirmDelete = " Are you sure to delete this file?"; diff --git a/module/file/lang/zh-cn.php b/module/file/lang/zh-cn.php index 69bcdb0c3d..f74c0421e8 100644 --- a/module/file/lang/zh-cn.php +++ b/module/file/lang/zh-cn.php @@ -1,23 +1,23 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->file->common = '附件'; -$lang->file->download = '下载附件'; -$lang->file->edit = '编辑附件名称'; -$lang->file->inputFileName = '请输入附件名称'; -$lang->file->delete = '删除附件'; -$lang->file->export2CSV = '导出CSV'; -$lang->file->ajaxUpload = '接口:编辑器上传附件'; -$lang->file->label = '标题:'; - -$lang->file->errorNotExists = "文件夹 '%s' 不存在"; -$lang->file->errorCanNotWrite = "文件夹 '%s' 不可写,请改变文件夹的权限。在linux中输入指令:sudo chmod -R 777 '%s'"; -$lang->file->confirmDelete = " 您确定删除该附件吗?"; + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->file->common = '附件'; +$lang->file->download = '下载附件'; +$lang->file->edit = '编辑附件名称'; +$lang->file->inputFileName = '请输入附件名称'; +$lang->file->delete = '删除附件'; +$lang->file->export2CSV = '导出CSV'; +$lang->file->ajaxUpload = '接口:编辑器上传附件'; +$lang->file->label = '标题:'; + +$lang->file->errorNotExists = "文件夹 '%s' 不存在"; +$lang->file->errorCanNotWrite = "文件夹 '%s' 不可写,请改变文件夹的权限。在linux中输入指令:sudo chmod -R 777 '%s'"; +$lang->file->confirmDelete = " 您确定删除该附件吗?"; diff --git a/module/file/lang/zh-tw.php b/module/file/lang/zh-tw.php index 472b327ad5..9c8c8f8f8f 100644 --- a/module/file/lang/zh-tw.php +++ b/module/file/lang/zh-tw.php @@ -1,23 +1,23 @@ - - * @package file - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->file->common = '附件'; -$lang->file->download = '下載附件'; -$lang->file->edit = '編輯附件名稱'; -$lang->file->inputFileName = '請輸入附件名稱'; -$lang->file->delete = '刪除附件'; -$lang->file->export2CSV = '導出CSV'; -$lang->file->ajaxUpload = '介面:編輯器上傳附件'; -$lang->file->label = '標題:'; - -$lang->file->errorNotExists = "檔案夾 '%s' 不存在"; -$lang->file->errorCanNotWrite = "檔案夾 '%s' 不可寫,請改變檔案夾的權限。在linux中輸入指令:sudo chmod -R 777 '%s'"; -$lang->file->confirmDelete = " 您確定刪除該附件嗎?"; + + * @package file + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->file->common = '附件'; +$lang->file->download = '下載附件'; +$lang->file->edit = '編輯附件名稱'; +$lang->file->inputFileName = '請輸入附件名稱'; +$lang->file->delete = '刪除附件'; +$lang->file->export2CSV = '導出CSV'; +$lang->file->ajaxUpload = '介面:編輯器上傳附件'; +$lang->file->label = '標題:'; + +$lang->file->errorNotExists = "檔案夾 '%s' 不存在"; +$lang->file->errorCanNotWrite = "檔案夾 '%s' 不可寫,請改變檔案夾的權限。在linux中輸入指令:sudo chmod -R 777 '%s'"; +$lang->file->confirmDelete = " 您確定刪除該附件嗎?"; diff --git a/module/file/model.php b/module/file/model.php index 681f1b7d03..dc1b9e9b2a 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -1,210 +1,210 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> -now = time(); - $this->setSavePath(); - $this->setWebPath(); - } - - /** - * Get files of an object. - * - * @param string $objectType - * @param string $objectID - * @access public - * @return array - */ - public function getByObject($objectType, $objectID) - { - return $this->dao->select('*')->from(TABLE_FILE)->where('objectType')->eq($objectType)->andWhere('objectID')->eq((int)$objectID)->orderBy('id')->fetchAll(); - } - - /** - * Get info of a file. - * - * @param int $fileID - * @access public - * @return object - */ - public function getById($fileID) - { - $file = $this->dao->findById($fileID)->from(TABLE_FILE)->fetch(); - $file->webPath = $this->webPath . $file->pathname; - $file->realPath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; - return $file; - } - - /** - * Save upload. - * - * @param string $objectType - * @param string $objectID - * @param string $extra - * @access public - * @return array - */ - public function saveUpload($objectType = '', $objectID = '', $extra = '') - { - $fileTitles = array(); - $now = helper::today(); - $files = $this->getUpload(); - - foreach($files as $id => $file) - { - move_uploaded_file($file['tmpname'], $this->savePath . $file['pathname']); - $file['objectType'] = $objectType; - $file['objectID'] = $objectID; - $file['addedBy'] = $this->app->user->account; - $file['addedDate'] = $now; - $file['extra'] = $extra; - unset($file['tmpname']); - $this->dao->insert(TABLE_FILE)->data($file)->exec(); - $fileTitles[$this->dao->lastInsertId()] = $file['title']; - } - return $fileTitles; - } - - /** - * Get counts of uploaded files. - * - * @access public - * @return int - */ - public function getCount() - { - return count($this->getUpload()); - } - - /** - * Get info of uploaded files. - * - * @param string $htmlTagName - * @access public - * @return array - */ - public function getUpload($htmlTagName = 'files') - { - $files = array(); - if(!isset($_FILES[$htmlTagName])) return $files; - - /* If the file var name is an array. */ - if(is_array($_FILES[$htmlTagName]['name'])) - { - extract($_FILES[$htmlTagName]); - foreach($name as $id => $filename) - { - if(empty($filename)) continue; - $file['extension'] = $this->getExtension($filename); - $file['pathname'] = $this->setPathName($id, $file['extension']); - $file['title'] = !empty($_POST['labels'][$id]) ? htmlspecialchars($_POST['labels'][$id]) : str_replace('.' . $file['extension'], '', $filename); - $file['size'] = $size[$id]; - $file['tmpname'] = $tmp_name[$id]; - $files[] = $file; - } - } - else - { - if(empty($_FILES[$htmlTagName]['name'])) return $files; - extract($_FILES[$htmlTagName]); - $file['extension'] = $this->getExtension($name); - $file['pathname'] = $this->setPathName(0, $file['extension']); - $file['title'] = !empty($_POST['labels'][0]) ? htmlspecialchars($_POST['labels'][0]) : substr($name, 0, strpos($name, $file['extension']) - 1); - $file['size'] = $size; - $file['tmpname'] = $tmp_name; - return array($file); - } - return $files; - } - - /** - * Get extension of a file. - * - * @param string $filename - * @access public - * @return string - */ - public function getExtension($filename) - { - $extension = pathinfo($filename, PATHINFO_EXTENSION); - if(empty($extension)) return 'txt'; - if(strpos($this->config->file->dangers, $extension) !== false) return 'txt'; - return $extension; - } - - /** - * Set path name of the uploaded file to be saved. - * - * @param int $fileID - * @param string $extension - * @access public - * @return string - */ - public function setPathName($fileID, $extension) - { - $sessionID = session_id(); - $randString = substr($sessionID, mt_rand(0, strlen($sessionID) - 5), 3); - return date('Ym/dHis', $this->now) . $fileID . mt_rand(0, 10000) . $randString . '.' . $extension; - } - - /** - * Set save path. - * - * @access public - * @return void - */ - public function setSavePath() - { - $savePath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . date('Ym/', $this->now); - if(!file_exists($savePath)) @mkdir($savePath, 0777, true); - $this->savePath = dirname($savePath) . '/'; - } - - /** - * Set the web path of upload files. - * - * @access public - * @return void - */ - public function setWebPath() - { - $this->webPath = $this->app->getWebRoot() . "data/upload/{$this->app->company->id}/"; - } - - /** - * Insert the set image size code. - * - * @param string $content - * @param int $maxSize - * @access public - * @return string - */ - public function setImgSize($content, $maxSize = 0) - { - return str_replace('src="data/upload', 'onload="setImageSize(this,' . $maxSize . ' )" src="data/upload', $content); - } -} + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> +now = time(); + $this->setSavePath(); + $this->setWebPath(); + } + + /** + * Get files of an object. + * + * @param string $objectType + * @param string $objectID + * @access public + * @return array + */ + public function getByObject($objectType, $objectID) + { + return $this->dao->select('*')->from(TABLE_FILE)->where('objectType')->eq($objectType)->andWhere('objectID')->eq((int)$objectID)->orderBy('id')->fetchAll(); + } + + /** + * Get info of a file. + * + * @param int $fileID + * @access public + * @return object + */ + public function getById($fileID) + { + $file = $this->dao->findById($fileID)->from(TABLE_FILE)->fetch(); + $file->webPath = $this->webPath . $file->pathname; + $file->realPath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; + return $file; + } + + /** + * Save upload. + * + * @param string $objectType + * @param string $objectID + * @param string $extra + * @access public + * @return array + */ + public function saveUpload($objectType = '', $objectID = '', $extra = '') + { + $fileTitles = array(); + $now = helper::today(); + $files = $this->getUpload(); + + foreach($files as $id => $file) + { + move_uploaded_file($file['tmpname'], $this->savePath . $file['pathname']); + $file['objectType'] = $objectType; + $file['objectID'] = $objectID; + $file['addedBy'] = $this->app->user->account; + $file['addedDate'] = $now; + $file['extra'] = $extra; + unset($file['tmpname']); + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + $fileTitles[$this->dao->lastInsertId()] = $file['title']; + } + return $fileTitles; + } + + /** + * Get counts of uploaded files. + * + * @access public + * @return int + */ + public function getCount() + { + return count($this->getUpload()); + } + + /** + * Get info of uploaded files. + * + * @param string $htmlTagName + * @access public + * @return array + */ + public function getUpload($htmlTagName = 'files') + { + $files = array(); + if(!isset($_FILES[$htmlTagName])) return $files; + + /* If the file var name is an array. */ + if(is_array($_FILES[$htmlTagName]['name'])) + { + extract($_FILES[$htmlTagName]); + foreach($name as $id => $filename) + { + if(empty($filename)) continue; + $file['extension'] = $this->getExtension($filename); + $file['pathname'] = $this->setPathName($id, $file['extension']); + $file['title'] = !empty($_POST['labels'][$id]) ? htmlspecialchars($_POST['labels'][$id]) : str_replace('.' . $file['extension'], '', $filename); + $file['size'] = $size[$id]; + $file['tmpname'] = $tmp_name[$id]; + $files[] = $file; + } + } + else + { + if(empty($_FILES[$htmlTagName]['name'])) return $files; + extract($_FILES[$htmlTagName]); + $file['extension'] = $this->getExtension($name); + $file['pathname'] = $this->setPathName(0, $file['extension']); + $file['title'] = !empty($_POST['labels'][0]) ? htmlspecialchars($_POST['labels'][0]) : substr($name, 0, strpos($name, $file['extension']) - 1); + $file['size'] = $size; + $file['tmpname'] = $tmp_name; + return array($file); + } + return $files; + } + + /** + * Get extension of a file. + * + * @param string $filename + * @access public + * @return string + */ + public function getExtension($filename) + { + $extension = pathinfo($filename, PATHINFO_EXTENSION); + if(empty($extension)) return 'txt'; + if(strpos($this->config->file->dangers, $extension) !== false) return 'txt'; + return $extension; + } + + /** + * Set path name of the uploaded file to be saved. + * + * @param int $fileID + * @param string $extension + * @access public + * @return string + */ + public function setPathName($fileID, $extension) + { + $sessionID = session_id(); + $randString = substr($sessionID, mt_rand(0, strlen($sessionID) - 5), 3); + return date('Ym/dHis', $this->now) . $fileID . mt_rand(0, 10000) . $randString . '.' . $extension; + } + + /** + * Set save path. + * + * @access public + * @return void + */ + public function setSavePath() + { + $savePath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . date('Ym/', $this->now); + if(!file_exists($savePath)) @mkdir($savePath, 0777, true); + $this->savePath = dirname($savePath) . '/'; + } + + /** + * Set the web path of upload files. + * + * @access public + * @return void + */ + public function setWebPath() + { + $this->webPath = $this->app->getWebRoot() . "data/upload/{$this->app->company->id}/"; + } + + /** + * Insert the set image size code. + * + * @param string $content + * @param int $maxSize + * @access public + * @return string + */ + public function setImgSize($content, $maxSize = 0) + { + return str_replace('src="data/upload', 'onload="setImageSize(this,' . $maxSize . ' )" src="data/upload', $content); + } +} diff --git a/module/file/view/edit.html.php b/module/file/view/edit.html.php index 5a565ab6ad..eaa739fdb7 100644 --- a/module/file/view/edit.html.php +++ b/module/file/view/edit.html.php @@ -1,41 +1,41 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          - - - - - -
          file->inputFileName;?>
          - title) . ".{$file->extension}";?> - -
          -
          - + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          + + + + + +
          file->inputFileName;?>
          + title) . ".{$file->extension}";?> + +
          +
          + diff --git a/module/file/view/export.html.php b/module/file/view/export.html.php index 63da5a10c5..df0087219c 100644 --- a/module/file/view/export.html.php +++ b/module/file/view/export.html.php @@ -1,51 +1,51 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -

          -
          - - - - - -
          export;?>
          - setFileName;?> - - exportFileTypeList);?> - -
          -
          - + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +

          +
          + + + + + +
          export;?>
          + setFileName;?> + + exportFileTypeList);?> + +
          +
          + diff --git a/module/file/view/export2csv.html.php b/module/file/view/export2csv.html.php index 51f3e347a5..1e8f1b53ca 100644 --- a/module/file/view/export2csv.html.php +++ b/module/file/view/export2csv.html.php @@ -1,24 +1,24 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> - $fieldLabel) - { - isset($row->$fieldName) ? print(strip_tags($row->$fieldName)) : print(''); - echo '","'; - } - echo '"' . "\n"; -} + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> + $fieldLabel) + { + isset($row->$fieldName) ? print(strip_tags($row->$fieldName)) : print(''); + echo '","'; + } + echo '"' . "\n"; +} diff --git a/module/file/view/export2html.html.php b/module/file/view/export2html.html.php index d174cd7155..c6d36ad2b6 100644 --- a/module/file/view/export2html.html.php +++ b/module/file/view/export2html.html.php @@ -1,44 +1,44 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -<?php echo $fileName;?> - - - - $fieldLabel\n"; - } - ?> - -\n"; - foreach($fields as $fieldName => $fieldLabel) - { - $fieldValue = isset($row->$fieldName) ? $row->$fieldName : ''; - echo "\n"; - } - echo "\n"; -} -?> -
          $fieldValue
          - - + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +<?php echo $fileName;?> + + + + $fieldLabel\n"; + } + ?> + +\n"; + foreach($fields as $fieldName => $fieldLabel) + { + $fieldValue = isset($row->$fieldName) ? $row->$fieldName : ''; + echo "\n"; + } + echo "\n"; +} +?> +
          $fieldValue
          + + diff --git a/module/file/view/export2xml.html.php b/module/file/view/export2xml.html.php index ac8059d1dc..3747ab98b7 100644 --- a/module/file/view/export2xml.html.php +++ b/module/file/view/export2xml.html.php @@ -1,36 +1,36 @@ - - * @package file - * @version $Id$ - * @link http://www.zentao.net - */ -?> -\n";?> - - $fieldLabel) -{ - echo " <$fieldName>$fieldLabel\n"; -} -?> - - -\n"; - foreach($fields as $fieldName => $fieldLabel) - { - $fieldValue = isset($row->$fieldName) ? htmlspecialchars($row->$fieldName) : ''; - echo " <$fieldName>$fieldValue\n"; - } - echo " \n"; -} -?> - - + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> +\n";?> + + $fieldLabel) +{ + echo " <$fieldName>$fieldLabel\n"; +} +?> + + +\n"; + foreach($fields as $fieldName => $fieldLabel) + { + $fieldValue = isset($row->$fieldName) ? htmlspecialchars($row->$fieldName) : ''; + echo " <$fieldName>$fieldValue\n"; + } + echo " \n"; +} +?> + + diff --git a/module/group/control.php b/module/group/control.php index d0baf0b20f..88f3cbbf0f 100644 --- a/module/group/control.php +++ b/module/group/control.php @@ -1,224 +1,224 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -class group extends control -{ - /** - * Construct function. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('company')->setMenu(); - $this->loadModel('user'); - } - - /** - * Browse groups. - * - * @param int $companyID - * @access public - * @return void - */ - public function browse($companyID = 0) - { - if($companyID == 0) $companyID = $this->app->company->id; - - $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->browse; - $position[] = $this->lang->group->browse; - - $groups = $this->group->getList($companyID); - $groupUsers = array(); - foreach($groups as $group) $groupUsers[$group->id] = $this->group->getUserPairs($group->id); - - $this->view->header = $header; - $this->view->position = $position; - $this->view->groups = $groups; - $this->view->groupUsers = $groupUsers; - - $this->display(); - } - - /** - * Create a group. - * - * @access public - * @return void - */ - public function create() - { - if(!empty($_POST)) - { - $this->group->create(); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('group', 'browse'), 'parent')); - } - - $this->view->header->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->create; - $this->view->position[] = $this->lang->group->create; - $this->display(); - } - - /** - * Edit a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function edit($groupID) - { - if(!empty($_POST)) - { - $this->group->update($groupID); - die(js::locate($this->createLink('group', 'browse'), 'parent')); - } - - $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->edit; - $position[] = $this->lang->group->edit; - $this->view->header = $header; - $this->view->position = $position; - $this->view->group = $this->group->getById($groupID); - - $this->display(); - } - - /** - * Copy a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function copy($groupID) - { - if(!empty($_POST)) - { - $this->group->copy($groupID); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('group', 'browse'), 'parent')); - } - - $this->view->header->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->copy; - $this->view->position[] = $this->lang->group->copy; - $this->view->group = $this->group->getById($groupID); - $this->display(); - } - - /** - * Manage privleges of a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function managePriv($type = 'byGroup', $param = 0) - { - if($type == 'byGroup') $groupID = $param; - $this->view->type = $type; - foreach($this->lang->resource as $moduleName => $action) $this->app->loadLang($moduleName); - - if(!empty($_POST)) - { - if($type == 'byGroup') $result = $this->group->updatePrivByGroup($groupID); - if($type == 'byModule') $result = $this->group->updatePrivByModule(); - print(js::alert($result ? $this->lang->group->successSaved : $this->lang->group->errorNotSaved)); - exit; - } - - if($type == 'byGroup') - { - $group = $this->group->getById($groupID); - $groupPrivs = $this->group->getPrivs($groupID); - - $this->view->header->title = $this->lang->company->common . $this->lang->colon . $group->name . $this->lang->colon . $this->lang->group->managePriv; - $this->view->position[] = $group->name . $this->lang->colon . $this->lang->group->managePriv; - - $this->view->group = $group; - $this->view->changelogs = $this->lang->changelog; - $this->view->groupPrivs = $groupPrivs; - - } - elseif($type == 'byModule') - { - $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->group->managePriv; - $this->view->position[] = $this->lang->group->managePriv; - - foreach($this->lang->resource as $module => $moduleActions) - { - $modules[$module] = $this->lang->$module->common; - foreach($moduleActions as $action) - { - $actions[$module][$action] = $this->lang->$module->$action; - } - } - $this->view->groups = $this->group->getPairs(); - $this->view->modules = $modules; - $this->view->actions = $actions; - } - $this->display(); - } - - /** - * Manage members of a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function manageMember($groupID) - { - if(!empty($_POST)) - { - $this->group->updateUser($groupID); - die(js::locate($this->createLink('group', 'browse'), 'parent')); - } - $group = $this->group->getById($groupID); - $groupUsers = $this->group->getUserPairs($groupID); - $allUsers = $this->user->getPairs('noclosed|noempty|noletter'); - $otherUsers = array_diff_assoc($allUsers, $groupUsers); - - $header['title'] = $this->lang->company->common . $this->lang->colon . $group->name . $this->lang->colon . $this->lang->group->manageMember; - $position[] = $group->name . $this->lang->colon . $this->lang->group->manageMember; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->group = $group; - $this->view->groupUsers = $groupUsers; - $this->view->otherUsers = $otherUsers; - - $this->display(); - } - - /** - * Delete a group. - * - * @param int $groupID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($groupID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->group->confirmDelete, $this->createLink('group', 'delete', "groupID=$groupID&confirm=yes"))); - } - else - { - $this->group->delete($groupID); - die(js::locate($this->createLink('group', 'browse'), 'parent')); - } - } -} + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +class group extends control +{ + /** + * Construct function. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('company')->setMenu(); + $this->loadModel('user'); + } + + /** + * Browse groups. + * + * @param int $companyID + * @access public + * @return void + */ + public function browse($companyID = 0) + { + if($companyID == 0) $companyID = $this->app->company->id; + + $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->browse; + $position[] = $this->lang->group->browse; + + $groups = $this->group->getList($companyID); + $groupUsers = array(); + foreach($groups as $group) $groupUsers[$group->id] = $this->group->getUserPairs($group->id); + + $this->view->header = $header; + $this->view->position = $position; + $this->view->groups = $groups; + $this->view->groupUsers = $groupUsers; + + $this->display(); + } + + /** + * Create a group. + * + * @access public + * @return void + */ + public function create() + { + if(!empty($_POST)) + { + $this->group->create(); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('group', 'browse'), 'parent')); + } + + $this->view->header->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->create; + $this->view->position[] = $this->lang->group->create; + $this->display(); + } + + /** + * Edit a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function edit($groupID) + { + if(!empty($_POST)) + { + $this->group->update($groupID); + die(js::locate($this->createLink('group', 'browse'), 'parent')); + } + + $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->edit; + $position[] = $this->lang->group->edit; + $this->view->header = $header; + $this->view->position = $position; + $this->view->group = $this->group->getById($groupID); + + $this->display(); + } + + /** + * Copy a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function copy($groupID) + { + if(!empty($_POST)) + { + $this->group->copy($groupID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('group', 'browse'), 'parent')); + } + + $this->view->header->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->copy; + $this->view->position[] = $this->lang->group->copy; + $this->view->group = $this->group->getById($groupID); + $this->display(); + } + + /** + * Manage privleges of a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function managePriv($type = 'byGroup', $param = 0) + { + if($type == 'byGroup') $groupID = $param; + $this->view->type = $type; + foreach($this->lang->resource as $moduleName => $action) $this->app->loadLang($moduleName); + + if(!empty($_POST)) + { + if($type == 'byGroup') $result = $this->group->updatePrivByGroup($groupID); + if($type == 'byModule') $result = $this->group->updatePrivByModule(); + print(js::alert($result ? $this->lang->group->successSaved : $this->lang->group->errorNotSaved)); + exit; + } + + if($type == 'byGroup') + { + $group = $this->group->getById($groupID); + $groupPrivs = $this->group->getPrivs($groupID); + + $this->view->header->title = $this->lang->company->common . $this->lang->colon . $group->name . $this->lang->colon . $this->lang->group->managePriv; + $this->view->position[] = $group->name . $this->lang->colon . $this->lang->group->managePriv; + + $this->view->group = $group; + $this->view->changelogs = $this->lang->changelog; + $this->view->groupPrivs = $groupPrivs; + + } + elseif($type == 'byModule') + { + $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->group->managePriv; + $this->view->position[] = $this->lang->group->managePriv; + + foreach($this->lang->resource as $module => $moduleActions) + { + $modules[$module] = $this->lang->$module->common; + foreach($moduleActions as $action) + { + $actions[$module][$action] = $this->lang->$module->$action; + } + } + $this->view->groups = $this->group->getPairs(); + $this->view->modules = $modules; + $this->view->actions = $actions; + } + $this->display(); + } + + /** + * Manage members of a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function manageMember($groupID) + { + if(!empty($_POST)) + { + $this->group->updateUser($groupID); + die(js::locate($this->createLink('group', 'browse'), 'parent')); + } + $group = $this->group->getById($groupID); + $groupUsers = $this->group->getUserPairs($groupID); + $allUsers = $this->user->getPairs('noclosed|noempty|noletter'); + $otherUsers = array_diff_assoc($allUsers, $groupUsers); + + $header['title'] = $this->lang->company->common . $this->lang->colon . $group->name . $this->lang->colon . $this->lang->group->manageMember; + $position[] = $group->name . $this->lang->colon . $this->lang->group->manageMember; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->group = $group; + $this->view->groupUsers = $groupUsers; + $this->view->otherUsers = $otherUsers; + + $this->display(); + } + + /** + * Delete a group. + * + * @param int $groupID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($groupID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->group->confirmDelete, $this->createLink('group', 'delete', "groupID=$groupID&confirm=yes"))); + } + else + { + $this->group->delete($groupID); + die(js::locate($this->createLink('group', 'browse'), 'parent')); + } + } +} diff --git a/module/group/lang/en.php b/module/group/lang/en.php index 369583b86f..6682b306f1 100644 --- a/module/group/lang/en.php +++ b/module/group/lang/en.php @@ -1,57 +1,57 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->group->common = 'Group'; -$lang->group->browse = 'Browse'; -$lang->group->create = 'Create'; -$lang->group->edit = 'Edit'; -$lang->group->copy = 'Copy'; -$lang->group->delete = 'Delete'; -$lang->group->managePriv = 'Privilege'; -$lang->group->managePrivByGroup = 'Privilege'; -$lang->group->managePrivByModule = 'Manage privilege by module'; -$lang->group->manageMember = 'Members'; -$lang->group->linkMember = 'Add members'; -$lang->group->unlinkMember = 'Remove member'; -$lang->group->confirmDelete = 'Are you sure to delete this group?'; -$lang->group->successSaved = 'Success saved.'; -$lang->group->errorNotSaved = 'Not saved, please make sure you have selected some actions and groups.'; - -$lang->group->id = 'Id'; -$lang->group->name = 'Name'; -$lang->group->desc = 'Desc'; -$lang->group->users = 'Users'; -$lang->group->module = 'Module'; -$lang->group->method = 'Method'; -$lang->group->priv = 'Priviledge'; -$lang->group->checkall = 'Select all'; -$lang->group->option = 'Option'; -$lang->group->inside = 'Group users'; -$lang->group->outside = 'Other users'; - -$lang->group->copyOptions['copyPriv'] = 'Copy priviledge'; -$lang->group->copyOptions['copyUser'] = 'Copy user'; - -$lang->group->versions[''] = 'Show methods added in every release'; -$lang->group->versions['3.0.beta1'] = '3.0.beta1'; -$lang->group->versions['2.4'] = '2.4'; -$lang->group->versions['2.3'] = '2.3'; -$lang->group->versions['2.2'] = '2.2'; -$lang->group->versions['2.1'] = '2.1'; -$lang->group->versions['2.0'] = '2.0'; -$lang->group->versions['1.5'] = '1.5'; -$lang->group->versions['1.4'] = '1.4'; -$lang->group->versions['1.3'] = '1.3'; -$lang->group->versions['1.2'] = '1.2'; -$lang->group->versions['1.1'] = '1.1'; -$lang->group->versions['1.0.1'] = '1.0.1'; - -include (dirname(__FILE__) . '/resource.php'); + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->group->common = 'Group'; +$lang->group->browse = 'Browse'; +$lang->group->create = 'Create'; +$lang->group->edit = 'Edit'; +$lang->group->copy = 'Copy'; +$lang->group->delete = 'Delete'; +$lang->group->managePriv = 'Privilege'; +$lang->group->managePrivByGroup = 'Privilege'; +$lang->group->managePrivByModule = 'Manage privilege by module'; +$lang->group->manageMember = 'Members'; +$lang->group->linkMember = 'Add members'; +$lang->group->unlinkMember = 'Remove member'; +$lang->group->confirmDelete = 'Are you sure to delete this group?'; +$lang->group->successSaved = 'Success saved.'; +$lang->group->errorNotSaved = 'Not saved, please make sure you have selected some actions and groups.'; + +$lang->group->id = 'Id'; +$lang->group->name = 'Name'; +$lang->group->desc = 'Desc'; +$lang->group->users = 'Users'; +$lang->group->module = 'Module'; +$lang->group->method = 'Method'; +$lang->group->priv = 'Priviledge'; +$lang->group->checkall = 'Select all'; +$lang->group->option = 'Option'; +$lang->group->inside = 'Group users'; +$lang->group->outside = 'Other users'; + +$lang->group->copyOptions['copyPriv'] = 'Copy priviledge'; +$lang->group->copyOptions['copyUser'] = 'Copy user'; + +$lang->group->versions[''] = 'Show methods added in every release'; +$lang->group->versions['3.0.beta1'] = '3.0.beta1'; +$lang->group->versions['2.4'] = '2.4'; +$lang->group->versions['2.3'] = '2.3'; +$lang->group->versions['2.2'] = '2.2'; +$lang->group->versions['2.1'] = '2.1'; +$lang->group->versions['2.0'] = '2.0'; +$lang->group->versions['1.5'] = '1.5'; +$lang->group->versions['1.4'] = '1.4'; +$lang->group->versions['1.3'] = '1.3'; +$lang->group->versions['1.2'] = '1.2'; +$lang->group->versions['1.1'] = '1.1'; +$lang->group->versions['1.0.1'] = '1.0.1'; + +include (dirname(__FILE__) . '/resource.php'); diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index 2e6ed0b61e..b01b91a484 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -1,358 +1,358 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ - -/* Index module. */ -$lang->resource->index->index = 'index'; - -/* My module. */ -$lang->resource->my->index = 'index'; -$lang->resource->my->todo = 'todo'; -$lang->resource->my->task = 'task'; -$lang->resource->my->bug = 'bug'; -$lang->resource->my->testTask = 'testTask'; -$lang->resource->my->testCase = 'testCase'; -$lang->resource->my->story = 'story'; -$lang->resource->my->project = 'myProject'; -$lang->resource->my->profile = 'profile'; -$lang->resource->my->dynamic = 'dynamic'; -$lang->resource->my->editProfile = 'editProfile'; - -/* Todo. */ -$lang->resource->todo->create = 'create'; -$lang->resource->todo->edit = 'edit'; -$lang->resource->todo->view = 'view'; -$lang->resource->todo->delete = 'delete'; -$lang->resource->todo->export = 'export'; -$lang->resource->todo->mark = 'mark'; -$lang->resource->todo->import2Today = 'import2Today'; - -/* Product. */ -$lang->resource->product->index = 'index'; -$lang->resource->product->browse = 'browse'; -$lang->resource->product->create = 'create'; -$lang->resource->product->view = 'view'; -$lang->resource->product->edit = 'edit'; -$lang->resource->product->delete = 'delete'; -$lang->resource->product->roadmap= 'roadmap'; -$lang->resource->product->doc = 'doc'; -$lang->resource->product->dynamic= 'dynamic'; -$lang->resource->product->project= 'project'; -$lang->resource->product->ajaxGetProjects = 'ajaxGetProjects'; -$lang->resource->product->ajaxGetPlans = 'ajaxGetPlans'; - -/* Story. */ -$lang->resource->story->create = 'create'; -$lang->resource->story->batchCreate = 'batchCreate'; -$lang->resource->story->edit = 'edit'; -$lang->resource->story->export = 'export'; -$lang->resource->story->delete = 'delete'; -$lang->resource->story->view = 'view'; -$lang->resource->story->change = 'lblChange'; -$lang->resource->story->review = 'lblReview'; -$lang->resource->story->close = 'lblClose'; -$lang->resource->story->activate = 'lblActivate'; -$lang->resource->story->tasks = 'tasks'; -$lang->resource->story->report = 'reportChart'; -$lang->resource->story->ajaxGetProjectStories = 'ajaxGetProjectStories'; -$lang->resource->story->ajaxGetProductStories = 'ajaxGetProductStories'; - -/* Product plan. */ -$lang->resource->productplan->browse = 'browse'; -$lang->resource->productplan->create = 'create'; -$lang->resource->productplan->edit = 'edit'; -$lang->resource->productplan->delete = 'delete'; -$lang->resource->productplan->view = 'view'; -$lang->resource->productplan->linkStory = 'linkStory'; -$lang->resource->productplan->unlinkStory = 'unlinkStory'; - -/* Release. */ -$lang->resource->release->browse = 'browse'; -$lang->resource->release->create = 'create'; -$lang->resource->release->edit = 'edit'; -$lang->resource->release->delete = 'delete'; -$lang->resource->release->view = 'view'; -$lang->resource->release->ajaxGetStoriesAndBugs = 'ajaxGetStoriesAndBugs'; - -/* Project. */ -$lang->resource->project->index = 'index'; -$lang->resource->project->view = 'view'; -$lang->resource->project->browse = 'browse'; -$lang->resource->project->create = 'create'; -$lang->resource->project->edit = 'edit'; -$lang->resource->project->delete = 'delete'; -$lang->resource->project->task = 'task'; -$lang->resource->project->grouptask = 'groupTask'; -$lang->resource->project->importtask = 'importTask'; -$lang->resource->project->importBug = 'importBug'; -$lang->resource->project->story = 'story'; -$lang->resource->project->build = 'build'; -$lang->resource->project->testtask = 'testtask'; -$lang->resource->project->bug = 'bug'; -$lang->resource->project->burn = 'burn'; -$lang->resource->project->computeBurn = 'computeBurn'; -$lang->resource->project->burnData = 'burnData'; -$lang->resource->project->team = 'team'; -$lang->resource->project->doc = 'doc'; -$lang->resource->project->dynamic = 'dynamic'; -$lang->resource->project->manageProducts = 'manageProducts'; -//$lang->resource->project->manageChilds = 'manageChilds'; -$lang->resource->project->manageMembers = 'manageMembers'; -$lang->resource->project->unlinkMember = 'unlinkMember'; -$lang->resource->project->linkStory = 'linkStory'; -$lang->resource->project->unlinkStory = 'unlinkStory'; -$lang->resource->project->ajaxGetProducts= 'ajaxGetProducts'; - -/* Task. */ -$lang->resource->task->create = 'create'; -$lang->resource->task->batchCreate = 'batchCreate'; -$lang->resource->task->edit = 'edit'; -$lang->resource->task->assignTo = 'assign'; -$lang->resource->task->start = 'start'; -$lang->resource->task->finish = 'finish'; -$lang->resource->task->cancel = 'cancel'; -$lang->resource->task->close = 'close'; -$lang->resource->task->batchClose = 'batchClose'; -$lang->resource->task->activate = 'activate'; -$lang->resource->task->delete = 'delete'; -$lang->resource->task->view = 'view'; -$lang->resource->task->export = 'export'; -$lang->resource->task->confirmStoryChange = 'confirmStoryChange'; -$lang->resource->task->ajaxGetUserTasks = 'ajaxGetUserTasks'; -$lang->resource->task->ajaxGetProjectTasks = 'ajaxGetProjectTasks'; -$lang->resource->task->report = 'reportChart'; - -/* Build. */ -$lang->resource->build->create = 'create'; -$lang->resource->build->edit = 'edit'; -$lang->resource->build->delete = 'delete'; -$lang->resource->build->view = 'view'; -$lang->resource->build->ajaxGetProductBuilds = 'ajaxGetProductBuilds'; -$lang->resource->build->ajaxGetProjectBuilds = 'ajaxGetProjectBuilds'; - -/* QA. */ -$lang->resource->qa->index = 'index'; - -/* Bug. */ -$lang->resource->bug->index = 'index'; -$lang->resource->bug->browse = 'browse'; -$lang->resource->bug->create = 'create'; -$lang->resource->bug->confirmBug = 'confirmBug'; -$lang->resource->bug->view = 'view'; -$lang->resource->bug->edit = 'edit'; -$lang->resource->bug->resolve = 'resolve'; -$lang->resource->bug->activate = 'activate'; -$lang->resource->bug->close = 'close'; -$lang->resource->bug->report = 'reportChart'; -$lang->resource->bug->export = 'export'; -$lang->resource->bug->confirmStoryChange = 'confirmStoryChange'; -$lang->resource->bug->delete = 'delete'; -$lang->resource->bug->saveTemplate = 'saveTemplate'; -$lang->resource->bug->deleteTemplate = 'deleteTemplate'; -$lang->resource->bug->customFields = 'customFields'; -$lang->resource->bug->ajaxGetUserBugs = 'ajaxGetUserBugs'; -$lang->resource->bug->ajaxGetModuleOwner = 'ajaxGetModuleOwner'; - -/* Test case. */ -$lang->resource->testcase->index = 'index'; -$lang->resource->testcase->browse = 'browse'; -$lang->resource->testcase->create = 'create'; -$lang->resource->testcase->batchCreate = 'batchCreate'; -$lang->resource->testcase->view = 'view'; -$lang->resource->testcase->edit = 'edit'; -$lang->resource->testcase->delete = 'delete'; -$lang->resource->testcase->export = 'export'; -$lang->resource->testcase->confirmStoryChange = 'confirmStoryChange'; - -/* Test task. */ -$lang->resource->testtask->index = 'index'; -$lang->resource->testtask->create = 'create'; -$lang->resource->testtask->browse = 'browse'; -$lang->resource->testtask->view = 'view'; -$lang->resource->testtask->cases = 'lblCases'; -$lang->resource->testtask->edit = 'edit'; -$lang->resource->testtask->delete = 'delete'; -$lang->resource->testtask->batchAssign = 'batchAssign'; -$lang->resource->testtask->linkcase = 'linkCase'; -$lang->resource->testtask->unlinkcase = 'lblUnlinkCase'; -$lang->resource->testtask->runcase = 'lblRunCase'; -$lang->resource->testtask->results = 'lblResults'; - -/* Doc. */ -$lang->resource->doc->index = 'index'; -$lang->resource->doc->browse = 'browse'; -$lang->resource->doc->createLib = 'createLib'; -$lang->resource->doc->editLib = 'editLib'; -$lang->resource->doc->deleteLib = 'deleteLib'; -$lang->resource->doc->create = 'create'; -$lang->resource->doc->view = 'view'; -$lang->resource->doc->edit = 'edit'; -$lang->resource->doc->delete = 'delete'; - -/* Subversion. */ -$lang->resource->svn->diff = 'diff'; -$lang->resource->svn->cat = 'cat'; -$lang->resource->svn->apiSync = 'apiSync'; - -/* Company. */ -$lang->resource->company->index = 'index'; -$lang->resource->company->browse = 'browse'; -$lang->resource->company->edit = 'edit'; -$lang->resource->company->dynamic= 'dynamic'; - -/* Department. */ -$lang->resource->dept->browse = 'browse'; -$lang->resource->dept->updateOrder = 'updateOrder'; -$lang->resource->dept->manageChild = 'manageChild'; -$lang->resource->dept->delete = 'delete'; - -/* Group. */ -$lang->resource->group->browse = 'browse'; -$lang->resource->group->create = 'create'; -$lang->resource->group->edit = 'edit'; -$lang->resource->group->copy = 'copy'; -$lang->resource->group->delete = 'delete'; -$lang->resource->group->managePriv = 'managePriv'; -$lang->resource->group->manageMember = 'manageMember'; - -/* User. */ -$lang->resource->user->create = 'create'; -$lang->resource->user->view = 'view'; -$lang->resource->user->edit = 'edit'; -$lang->resource->user->delete = 'delete'; -$lang->resource->user->todo = 'todo'; -$lang->resource->user->task = 'task'; -$lang->resource->user->bug = 'bug'; -$lang->resource->user->project = 'project'; -$lang->resource->user->dynamic = 'dynamic'; -$lang->resource->user->profile = 'profile'; -$lang->resource->user->ajaxGetUser = 'ajaxGetUser'; - -/* Tree. */ -$lang->resource->tree->browse = 'browse'; -$lang->resource->tree->updateOrder = 'updateOrder'; -$lang->resource->tree->manageChild = 'manageChild'; -$lang->resource->tree->edit = 'edit'; -$lang->resource->tree->delete = 'delete'; -$lang->resource->tree->ajaxGetOptionMenu = 'ajaxGetOptionMenu'; -$lang->resource->tree->ajaxGetSonModules = 'ajaxGetSonModules'; - -/* Search. */ -$lang->resource->search->buildForm = 'buildForm'; -$lang->resource->search->buildQuery = 'buildQuery'; -$lang->resource->search->saveQuery = 'saveQuery'; -$lang->resource->search->deleteQuery = 'deleteQuery'; -$lang->resource->search->select = 'select'; - -/* Admin. */ -$lang->resource->admin->index = 'index'; - -/* Extension. */ -$lang->resource->extension->browse = 'browse'; -$lang->resource->extension->obtain = 'obtain'; -$lang->resource->extension->install = 'install'; -$lang->resource->extension->uninstall = 'uninstall'; -$lang->resource->extension->activate = 'activate'; -$lang->resource->extension->deactivate = 'deactivate'; -$lang->resource->extension->upload = 'upload'; -$lang->resource->extension->erase = 'erase'; -$lang->resource->extension->upgrade = 'upgrade'; - -/* Others. */ -$lang->resource->api->getModel = 'getModel'; -$lang->resource->file->download = 'download'; -$lang->resource->file->edit = 'edit'; -$lang->resource->file->delete = 'delete'; -$lang->resource->file->ajaxUpload = 'ajaxUpload'; -$lang->resource->misc->ping = 'ping'; -$lang->resource->action->trash = 'trash'; -$lang->resource->action->undelete = 'undelete'; - -/* Every version of new privilege. */ -$lang->changelog['1.0.1'][] = 'project-computeBurn'; - -$lang->changelog['1.1'][] = 'search-saveQuery'; -$lang->changelog['1.1'][] = 'search-deleteQuery'; - -$lang->changelog['1.2'][] = 'product-doc'; -$lang->changelog['1.2'][] = 'project-doc'; -$lang->changelog['1.2'][] = 'project-ajaxGetProducts'; -$lang->changelog['1.2'][] = 'bug-saveTemplate'; -$lang->changelog['1.2'][] = 'bug-deleteTemplate'; -$lang->changelog['1.2'][] = 'bug-customFields'; -$lang->changelog['1.2'][] = 'bug-ajaxGetModuleOwner'; -$lang->changelog['1.2'][] = 'doc-index'; -$lang->changelog['1.2'][] = 'doc-browse'; -$lang->changelog['1.2'][] = 'doc-createLib'; -$lang->changelog['1.2'][] = 'doc-editLib'; -$lang->changelog['1.2'][] = 'doc-deleteLib'; -$lang->changelog['1.2'][] = 'doc-create'; -$lang->changelog['1.2'][] = 'doc-view'; -$lang->changelog['1.2'][] = 'doc-edit'; -$lang->changelog['1.2'][] = 'doc-delete'; -$lang->changelog['1.2'][] = 'doc-deleteFile'; - -$lang->changelog['1.3'][] = 'task-start'; -$lang->changelog['1.3'][] = 'task-complete'; -$lang->changelog['1.3'][] = 'task-cancel'; -$lang->changelog['1.3'][] = 'tree-ajaxGetSonModules'; -$lang->changelog['1.3'][] = 'file-delete'; -$lang->changelog['1.3'][] = 'file-ajaxUpload'; - -$lang->changelog['1.4'][] = 'my-testTask'; -$lang->changelog['1.4'][] = 'my-testCase'; -$lang->changelog['1.4'][] = 'task-finish'; -$lang->changelog['1.4'][] = 'task-close'; -$lang->changelog['1.4'][] = 'task-activate'; -$lang->changelog['1.4'][] = 'search-select'; - -$lang->changelog['1.5'][] = 'task-batchClose'; - -$lang->changelog['2.0'][] = 'my-dynamic'; -$lang->changelog['2.0'][] = 'bug-export'; -$lang->changelog['2.0'][] = 'story-export'; -$lang->changelog['2.0'][] = 'story-reportChart'; -$lang->changelog['2.0'][] = 'task-export'; -$lang->changelog['2.0'][] = 'task-reportChart'; -$lang->changelog['2.0'][] = 'taskcase-export'; -$lang->changelog['2.0'][] = 'company-dynamic'; -$lang->changelog['2.0'][] = 'user-dynamic'; -$lang->changelog['2.0'][] = 'extension-browse'; -$lang->changelog['2.0'][] = 'extension-obtain'; -$lang->changelog['2.0'][] = 'extension-install'; -$lang->changelog['2.0'][] = 'extension-uninstall'; -$lang->changelog['2.0'][] = 'extension-activate'; -$lang->changelog['2.0'][] = 'extension-deactivate'; -$lang->changelog['2.0'][] = 'extension-upload'; -$lang->changelog['2.0'][] = 'extension-erase'; - -$lang->changelog['2.1'][] = 'extension-upgrade'; - -$lang->changelog['2.2'][] = 'file-edit'; - -$lang->changelog['2.3'][] = 'product-dynamic'; -$lang->changelog['2.3'][] = 'project-dynamic'; -$lang->changelog['2.3'][] = 'project-importBug'; -$lang->changelog['2.3'][] = 'story-batchCreate'; -$lang->changelog['2.3'][] = 'task-batchCreate'; -$lang->changelog['2.3'][] = 'testcase-batchCreate'; -$lang->changelog['2.3'][] = 'bug-confirmBug'; -$lang->changelog['2.3'][] = 'svn-diff'; -$lang->changelog['2.3'][] = 'svn-cat'; -$lang->changelog['2.3'][] = 'svn-apiSync'; - -$lang->changelog['2.4'][] = 'user-ajaxGetUser'; -$lang->changelog['2.4'][] = 'task-assign'; -$lang->changelog['2.4'][] = 'project-testtask'; -$lang->changelog['2.4'][] = 'todo-export'; -$lang->changelog['2.4'][] = 'product-project'; - -$lang->changelog['3.0.beta1'][] = 'release-ajaxGetStoriesAndBugs'; + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ + +/* Index module. */ +$lang->resource->index->index = 'index'; + +/* My module. */ +$lang->resource->my->index = 'index'; +$lang->resource->my->todo = 'todo'; +$lang->resource->my->task = 'task'; +$lang->resource->my->bug = 'bug'; +$lang->resource->my->testTask = 'testTask'; +$lang->resource->my->testCase = 'testCase'; +$lang->resource->my->story = 'story'; +$lang->resource->my->project = 'myProject'; +$lang->resource->my->profile = 'profile'; +$lang->resource->my->dynamic = 'dynamic'; +$lang->resource->my->editProfile = 'editProfile'; + +/* Todo. */ +$lang->resource->todo->create = 'create'; +$lang->resource->todo->edit = 'edit'; +$lang->resource->todo->view = 'view'; +$lang->resource->todo->delete = 'delete'; +$lang->resource->todo->export = 'export'; +$lang->resource->todo->mark = 'mark'; +$lang->resource->todo->import2Today = 'import2Today'; + +/* Product. */ +$lang->resource->product->index = 'index'; +$lang->resource->product->browse = 'browse'; +$lang->resource->product->create = 'create'; +$lang->resource->product->view = 'view'; +$lang->resource->product->edit = 'edit'; +$lang->resource->product->delete = 'delete'; +$lang->resource->product->roadmap= 'roadmap'; +$lang->resource->product->doc = 'doc'; +$lang->resource->product->dynamic= 'dynamic'; +$lang->resource->product->project= 'project'; +$lang->resource->product->ajaxGetProjects = 'ajaxGetProjects'; +$lang->resource->product->ajaxGetPlans = 'ajaxGetPlans'; + +/* Story. */ +$lang->resource->story->create = 'create'; +$lang->resource->story->batchCreate = 'batchCreate'; +$lang->resource->story->edit = 'edit'; +$lang->resource->story->export = 'export'; +$lang->resource->story->delete = 'delete'; +$lang->resource->story->view = 'view'; +$lang->resource->story->change = 'lblChange'; +$lang->resource->story->review = 'lblReview'; +$lang->resource->story->close = 'lblClose'; +$lang->resource->story->activate = 'lblActivate'; +$lang->resource->story->tasks = 'tasks'; +$lang->resource->story->report = 'reportChart'; +$lang->resource->story->ajaxGetProjectStories = 'ajaxGetProjectStories'; +$lang->resource->story->ajaxGetProductStories = 'ajaxGetProductStories'; + +/* Product plan. */ +$lang->resource->productplan->browse = 'browse'; +$lang->resource->productplan->create = 'create'; +$lang->resource->productplan->edit = 'edit'; +$lang->resource->productplan->delete = 'delete'; +$lang->resource->productplan->view = 'view'; +$lang->resource->productplan->linkStory = 'linkStory'; +$lang->resource->productplan->unlinkStory = 'unlinkStory'; + +/* Release. */ +$lang->resource->release->browse = 'browse'; +$lang->resource->release->create = 'create'; +$lang->resource->release->edit = 'edit'; +$lang->resource->release->delete = 'delete'; +$lang->resource->release->view = 'view'; +$lang->resource->release->ajaxGetStoriesAndBugs = 'ajaxGetStoriesAndBugs'; + +/* Project. */ +$lang->resource->project->index = 'index'; +$lang->resource->project->view = 'view'; +$lang->resource->project->browse = 'browse'; +$lang->resource->project->create = 'create'; +$lang->resource->project->edit = 'edit'; +$lang->resource->project->delete = 'delete'; +$lang->resource->project->task = 'task'; +$lang->resource->project->grouptask = 'groupTask'; +$lang->resource->project->importtask = 'importTask'; +$lang->resource->project->importBug = 'importBug'; +$lang->resource->project->story = 'story'; +$lang->resource->project->build = 'build'; +$lang->resource->project->testtask = 'testtask'; +$lang->resource->project->bug = 'bug'; +$lang->resource->project->burn = 'burn'; +$lang->resource->project->computeBurn = 'computeBurn'; +$lang->resource->project->burnData = 'burnData'; +$lang->resource->project->team = 'team'; +$lang->resource->project->doc = 'doc'; +$lang->resource->project->dynamic = 'dynamic'; +$lang->resource->project->manageProducts = 'manageProducts'; +//$lang->resource->project->manageChilds = 'manageChilds'; +$lang->resource->project->manageMembers = 'manageMembers'; +$lang->resource->project->unlinkMember = 'unlinkMember'; +$lang->resource->project->linkStory = 'linkStory'; +$lang->resource->project->unlinkStory = 'unlinkStory'; +$lang->resource->project->ajaxGetProducts= 'ajaxGetProducts'; + +/* Task. */ +$lang->resource->task->create = 'create'; +$lang->resource->task->batchCreate = 'batchCreate'; +$lang->resource->task->edit = 'edit'; +$lang->resource->task->assignTo = 'assign'; +$lang->resource->task->start = 'start'; +$lang->resource->task->finish = 'finish'; +$lang->resource->task->cancel = 'cancel'; +$lang->resource->task->close = 'close'; +$lang->resource->task->batchClose = 'batchClose'; +$lang->resource->task->activate = 'activate'; +$lang->resource->task->delete = 'delete'; +$lang->resource->task->view = 'view'; +$lang->resource->task->export = 'export'; +$lang->resource->task->confirmStoryChange = 'confirmStoryChange'; +$lang->resource->task->ajaxGetUserTasks = 'ajaxGetUserTasks'; +$lang->resource->task->ajaxGetProjectTasks = 'ajaxGetProjectTasks'; +$lang->resource->task->report = 'reportChart'; + +/* Build. */ +$lang->resource->build->create = 'create'; +$lang->resource->build->edit = 'edit'; +$lang->resource->build->delete = 'delete'; +$lang->resource->build->view = 'view'; +$lang->resource->build->ajaxGetProductBuilds = 'ajaxGetProductBuilds'; +$lang->resource->build->ajaxGetProjectBuilds = 'ajaxGetProjectBuilds'; + +/* QA. */ +$lang->resource->qa->index = 'index'; + +/* Bug. */ +$lang->resource->bug->index = 'index'; +$lang->resource->bug->browse = 'browse'; +$lang->resource->bug->create = 'create'; +$lang->resource->bug->confirmBug = 'confirmBug'; +$lang->resource->bug->view = 'view'; +$lang->resource->bug->edit = 'edit'; +$lang->resource->bug->resolve = 'resolve'; +$lang->resource->bug->activate = 'activate'; +$lang->resource->bug->close = 'close'; +$lang->resource->bug->report = 'reportChart'; +$lang->resource->bug->export = 'export'; +$lang->resource->bug->confirmStoryChange = 'confirmStoryChange'; +$lang->resource->bug->delete = 'delete'; +$lang->resource->bug->saveTemplate = 'saveTemplate'; +$lang->resource->bug->deleteTemplate = 'deleteTemplate'; +$lang->resource->bug->customFields = 'customFields'; +$lang->resource->bug->ajaxGetUserBugs = 'ajaxGetUserBugs'; +$lang->resource->bug->ajaxGetModuleOwner = 'ajaxGetModuleOwner'; + +/* Test case. */ +$lang->resource->testcase->index = 'index'; +$lang->resource->testcase->browse = 'browse'; +$lang->resource->testcase->create = 'create'; +$lang->resource->testcase->batchCreate = 'batchCreate'; +$lang->resource->testcase->view = 'view'; +$lang->resource->testcase->edit = 'edit'; +$lang->resource->testcase->delete = 'delete'; +$lang->resource->testcase->export = 'export'; +$lang->resource->testcase->confirmStoryChange = 'confirmStoryChange'; + +/* Test task. */ +$lang->resource->testtask->index = 'index'; +$lang->resource->testtask->create = 'create'; +$lang->resource->testtask->browse = 'browse'; +$lang->resource->testtask->view = 'view'; +$lang->resource->testtask->cases = 'lblCases'; +$lang->resource->testtask->edit = 'edit'; +$lang->resource->testtask->delete = 'delete'; +$lang->resource->testtask->batchAssign = 'batchAssign'; +$lang->resource->testtask->linkcase = 'linkCase'; +$lang->resource->testtask->unlinkcase = 'lblUnlinkCase'; +$lang->resource->testtask->runcase = 'lblRunCase'; +$lang->resource->testtask->results = 'lblResults'; + +/* Doc. */ +$lang->resource->doc->index = 'index'; +$lang->resource->doc->browse = 'browse'; +$lang->resource->doc->createLib = 'createLib'; +$lang->resource->doc->editLib = 'editLib'; +$lang->resource->doc->deleteLib = 'deleteLib'; +$lang->resource->doc->create = 'create'; +$lang->resource->doc->view = 'view'; +$lang->resource->doc->edit = 'edit'; +$lang->resource->doc->delete = 'delete'; + +/* Subversion. */ +$lang->resource->svn->diff = 'diff'; +$lang->resource->svn->cat = 'cat'; +$lang->resource->svn->apiSync = 'apiSync'; + +/* Company. */ +$lang->resource->company->index = 'index'; +$lang->resource->company->browse = 'browse'; +$lang->resource->company->edit = 'edit'; +$lang->resource->company->dynamic= 'dynamic'; + +/* Department. */ +$lang->resource->dept->browse = 'browse'; +$lang->resource->dept->updateOrder = 'updateOrder'; +$lang->resource->dept->manageChild = 'manageChild'; +$lang->resource->dept->delete = 'delete'; + +/* Group. */ +$lang->resource->group->browse = 'browse'; +$lang->resource->group->create = 'create'; +$lang->resource->group->edit = 'edit'; +$lang->resource->group->copy = 'copy'; +$lang->resource->group->delete = 'delete'; +$lang->resource->group->managePriv = 'managePriv'; +$lang->resource->group->manageMember = 'manageMember'; + +/* User. */ +$lang->resource->user->create = 'create'; +$lang->resource->user->view = 'view'; +$lang->resource->user->edit = 'edit'; +$lang->resource->user->delete = 'delete'; +$lang->resource->user->todo = 'todo'; +$lang->resource->user->task = 'task'; +$lang->resource->user->bug = 'bug'; +$lang->resource->user->project = 'project'; +$lang->resource->user->dynamic = 'dynamic'; +$lang->resource->user->profile = 'profile'; +$lang->resource->user->ajaxGetUser = 'ajaxGetUser'; + +/* Tree. */ +$lang->resource->tree->browse = 'browse'; +$lang->resource->tree->updateOrder = 'updateOrder'; +$lang->resource->tree->manageChild = 'manageChild'; +$lang->resource->tree->edit = 'edit'; +$lang->resource->tree->delete = 'delete'; +$lang->resource->tree->ajaxGetOptionMenu = 'ajaxGetOptionMenu'; +$lang->resource->tree->ajaxGetSonModules = 'ajaxGetSonModules'; + +/* Search. */ +$lang->resource->search->buildForm = 'buildForm'; +$lang->resource->search->buildQuery = 'buildQuery'; +$lang->resource->search->saveQuery = 'saveQuery'; +$lang->resource->search->deleteQuery = 'deleteQuery'; +$lang->resource->search->select = 'select'; + +/* Admin. */ +$lang->resource->admin->index = 'index'; + +/* Extension. */ +$lang->resource->extension->browse = 'browse'; +$lang->resource->extension->obtain = 'obtain'; +$lang->resource->extension->install = 'install'; +$lang->resource->extension->uninstall = 'uninstall'; +$lang->resource->extension->activate = 'activate'; +$lang->resource->extension->deactivate = 'deactivate'; +$lang->resource->extension->upload = 'upload'; +$lang->resource->extension->erase = 'erase'; +$lang->resource->extension->upgrade = 'upgrade'; + +/* Others. */ +$lang->resource->api->getModel = 'getModel'; +$lang->resource->file->download = 'download'; +$lang->resource->file->edit = 'edit'; +$lang->resource->file->delete = 'delete'; +$lang->resource->file->ajaxUpload = 'ajaxUpload'; +$lang->resource->misc->ping = 'ping'; +$lang->resource->action->trash = 'trash'; +$lang->resource->action->undelete = 'undelete'; + +/* Every version of new privilege. */ +$lang->changelog['1.0.1'][] = 'project-computeBurn'; + +$lang->changelog['1.1'][] = 'search-saveQuery'; +$lang->changelog['1.1'][] = 'search-deleteQuery'; + +$lang->changelog['1.2'][] = 'product-doc'; +$lang->changelog['1.2'][] = 'project-doc'; +$lang->changelog['1.2'][] = 'project-ajaxGetProducts'; +$lang->changelog['1.2'][] = 'bug-saveTemplate'; +$lang->changelog['1.2'][] = 'bug-deleteTemplate'; +$lang->changelog['1.2'][] = 'bug-customFields'; +$lang->changelog['1.2'][] = 'bug-ajaxGetModuleOwner'; +$lang->changelog['1.2'][] = 'doc-index'; +$lang->changelog['1.2'][] = 'doc-browse'; +$lang->changelog['1.2'][] = 'doc-createLib'; +$lang->changelog['1.2'][] = 'doc-editLib'; +$lang->changelog['1.2'][] = 'doc-deleteLib'; +$lang->changelog['1.2'][] = 'doc-create'; +$lang->changelog['1.2'][] = 'doc-view'; +$lang->changelog['1.2'][] = 'doc-edit'; +$lang->changelog['1.2'][] = 'doc-delete'; +$lang->changelog['1.2'][] = 'doc-deleteFile'; + +$lang->changelog['1.3'][] = 'task-start'; +$lang->changelog['1.3'][] = 'task-complete'; +$lang->changelog['1.3'][] = 'task-cancel'; +$lang->changelog['1.3'][] = 'tree-ajaxGetSonModules'; +$lang->changelog['1.3'][] = 'file-delete'; +$lang->changelog['1.3'][] = 'file-ajaxUpload'; + +$lang->changelog['1.4'][] = 'my-testTask'; +$lang->changelog['1.4'][] = 'my-testCase'; +$lang->changelog['1.4'][] = 'task-finish'; +$lang->changelog['1.4'][] = 'task-close'; +$lang->changelog['1.4'][] = 'task-activate'; +$lang->changelog['1.4'][] = 'search-select'; + +$lang->changelog['1.5'][] = 'task-batchClose'; + +$lang->changelog['2.0'][] = 'my-dynamic'; +$lang->changelog['2.0'][] = 'bug-export'; +$lang->changelog['2.0'][] = 'story-export'; +$lang->changelog['2.0'][] = 'story-reportChart'; +$lang->changelog['2.0'][] = 'task-export'; +$lang->changelog['2.0'][] = 'task-reportChart'; +$lang->changelog['2.0'][] = 'taskcase-export'; +$lang->changelog['2.0'][] = 'company-dynamic'; +$lang->changelog['2.0'][] = 'user-dynamic'; +$lang->changelog['2.0'][] = 'extension-browse'; +$lang->changelog['2.0'][] = 'extension-obtain'; +$lang->changelog['2.0'][] = 'extension-install'; +$lang->changelog['2.0'][] = 'extension-uninstall'; +$lang->changelog['2.0'][] = 'extension-activate'; +$lang->changelog['2.0'][] = 'extension-deactivate'; +$lang->changelog['2.0'][] = 'extension-upload'; +$lang->changelog['2.0'][] = 'extension-erase'; + +$lang->changelog['2.1'][] = 'extension-upgrade'; + +$lang->changelog['2.2'][] = 'file-edit'; + +$lang->changelog['2.3'][] = 'product-dynamic'; +$lang->changelog['2.3'][] = 'project-dynamic'; +$lang->changelog['2.3'][] = 'project-importBug'; +$lang->changelog['2.3'][] = 'story-batchCreate'; +$lang->changelog['2.3'][] = 'task-batchCreate'; +$lang->changelog['2.3'][] = 'testcase-batchCreate'; +$lang->changelog['2.3'][] = 'bug-confirmBug'; +$lang->changelog['2.3'][] = 'svn-diff'; +$lang->changelog['2.3'][] = 'svn-cat'; +$lang->changelog['2.3'][] = 'svn-apiSync'; + +$lang->changelog['2.4'][] = 'user-ajaxGetUser'; +$lang->changelog['2.4'][] = 'task-assign'; +$lang->changelog['2.4'][] = 'project-testtask'; +$lang->changelog['2.4'][] = 'todo-export'; +$lang->changelog['2.4'][] = 'product-project'; + +$lang->changelog['3.0.beta1'][] = 'release-ajaxGetStoriesAndBugs'; diff --git a/module/group/lang/zh-cn.php b/module/group/lang/zh-cn.php index bf6c48798b..897b1b1851 100644 --- a/module/group/lang/zh-cn.php +++ b/module/group/lang/zh-cn.php @@ -1,57 +1,57 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->group->common = '权限分组'; -$lang->group->browse = '浏览分组'; -$lang->group->create = '新增分组'; -$lang->group->edit = '编辑分组'; -$lang->group->copy = '复制分组'; -$lang->group->delete = '删除分组'; -$lang->group->managePriv = '权限维护'; -$lang->group->managePrivByGroup = '权限维护'; -$lang->group->managePrivByModule = '按模块分配权限'; -$lang->group->manageMember = '成员维护'; -$lang->group->linkMember = '关联用户'; -$lang->group->unlinkMember = '移除用户'; -$lang->group->confirmDelete = '您确定删除该用户分组吗?'; -$lang->group->successSaved = '成功保存'; -$lang->group->errorNotSaved = '没有保存,请确认选择了权限数据。'; - -$lang->group->id = '编号'; -$lang->group->name = '分组名称'; -$lang->group->desc = '分组描述'; -$lang->group->users = '用户列表'; -$lang->group->module = '模块'; -$lang->group->method = '方法'; -$lang->group->priv = '权限'; -$lang->group->checkall = '全选'; -$lang->group->option = '选项'; -$lang->group->inside = '组内用户'; -$lang->group->outside = '组外用户'; - -$lang->group->copyOptions['copyPriv'] = '复制权限'; -$lang->group->copyOptions['copyUser'] = '复制用户'; - -$lang->group->versions[''] = '显示各版本新增权限'; -$lang->group->versions['3.0.beta1'] = '禅道3.0.beta1'; -$lang->group->versions['2.4'] = '禅道2.4'; -$lang->group->versions['2.3'] = '禅道2.3'; -$lang->group->versions['2.2'] = '禅道2.2'; -$lang->group->versions['2.1'] = '禅道2.1'; -$lang->group->versions['2.0'] = '禅道2.0'; -$lang->group->versions['1.5'] = '禅道1.5'; -$lang->group->versions['1.4'] = '禅道1.4'; -$lang->group->versions['1.3'] = '禅道1.3'; -$lang->group->versions['1.2'] = '禅道1.2'; -$lang->group->versions['1.1'] = '禅道1.1'; -$lang->group->versions['1.0.1'] = '禅道1.0.1'; - -include (dirname(__FILE__) . '/resource.php'); + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->group->common = '权限分组'; +$lang->group->browse = '浏览分组'; +$lang->group->create = '新增分组'; +$lang->group->edit = '编辑分组'; +$lang->group->copy = '复制分组'; +$lang->group->delete = '删除分组'; +$lang->group->managePriv = '权限维护'; +$lang->group->managePrivByGroup = '权限维护'; +$lang->group->managePrivByModule = '按模块分配权限'; +$lang->group->manageMember = '成员维护'; +$lang->group->linkMember = '关联用户'; +$lang->group->unlinkMember = '移除用户'; +$lang->group->confirmDelete = '您确定删除该用户分组吗?'; +$lang->group->successSaved = '成功保存'; +$lang->group->errorNotSaved = '没有保存,请确认选择了权限数据。'; + +$lang->group->id = '编号'; +$lang->group->name = '分组名称'; +$lang->group->desc = '分组描述'; +$lang->group->users = '用户列表'; +$lang->group->module = '模块'; +$lang->group->method = '方法'; +$lang->group->priv = '权限'; +$lang->group->checkall = '全选'; +$lang->group->option = '选项'; +$lang->group->inside = '组内用户'; +$lang->group->outside = '组外用户'; + +$lang->group->copyOptions['copyPriv'] = '复制权限'; +$lang->group->copyOptions['copyUser'] = '复制用户'; + +$lang->group->versions[''] = '显示各版本新增权限'; +$lang->group->versions['3.0.beta1'] = '禅道3.0.beta1'; +$lang->group->versions['2.4'] = '禅道2.4'; +$lang->group->versions['2.3'] = '禅道2.3'; +$lang->group->versions['2.2'] = '禅道2.2'; +$lang->group->versions['2.1'] = '禅道2.1'; +$lang->group->versions['2.0'] = '禅道2.0'; +$lang->group->versions['1.5'] = '禅道1.5'; +$lang->group->versions['1.4'] = '禅道1.4'; +$lang->group->versions['1.3'] = '禅道1.3'; +$lang->group->versions['1.2'] = '禅道1.2'; +$lang->group->versions['1.1'] = '禅道1.1'; +$lang->group->versions['1.0.1'] = '禅道1.0.1'; + +include (dirname(__FILE__) . '/resource.php'); diff --git a/module/group/lang/zh-tw.php b/module/group/lang/zh-tw.php index f27604cc3c..7ea3efa832 100644 --- a/module/group/lang/zh-tw.php +++ b/module/group/lang/zh-tw.php @@ -1,57 +1,57 @@ - - * @package group - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->group->common = '權限分組'; -$lang->group->browse = '瀏覽分組'; -$lang->group->create = '新增分組'; -$lang->group->edit = '編輯分組'; -$lang->group->copy = '複製分組'; -$lang->group->delete = '刪除分組'; -$lang->group->managePriv = '權限維護'; -$lang->group->managePrivByGroup = '權限維護'; -$lang->group->managePrivByModule = '按模組分配權限'; -$lang->group->manageMember = '成員維護'; -$lang->group->linkMember = '關聯用戶'; -$lang->group->unlinkMember = '移除用戶'; -$lang->group->confirmDelete = '您確定刪除該用戶分組嗎?'; -$lang->group->successSaved = '成功保存'; -$lang->group->errorNotSaved = '沒有保存,請確認選擇了權限數據。'; - -$lang->group->id = '編號'; -$lang->group->name = '分組名稱'; -$lang->group->desc = '分組描述'; -$lang->group->users = '用戶列表'; -$lang->group->module = '模組'; -$lang->group->method = '方法'; -$lang->group->priv = '權限'; -$lang->group->checkall = '全選'; -$lang->group->option = '選項'; -$lang->group->inside = '組內用戶'; -$lang->group->outside = '組外用戶'; - -$lang->group->copyOptions['copyPriv'] = '複製權限'; -$lang->group->copyOptions['copyUser'] = '複製用戶'; - -$lang->group->versions[''] = '顯示各版本新增權限'; -$lang->group->versions['3.0.beta1'] = '禪道3.0.beta1'; -$lang->group->versions['2.4'] = '禪道2.4'; -$lang->group->versions['2.3'] = '禪道2.3'; -$lang->group->versions['2.2'] = '禪道2.2'; -$lang->group->versions['2.1'] = '禪道2.1'; -$lang->group->versions['2.0'] = '禪道2.0'; -$lang->group->versions['1.5'] = '禪道1.5'; -$lang->group->versions['1.4'] = '禪道1.4'; -$lang->group->versions['1.3'] = '禪道1.3'; -$lang->group->versions['1.2'] = '禪道1.2'; -$lang->group->versions['1.1'] = '禪道1.1'; -$lang->group->versions['1.0.1'] = '禪道1.0.1'; - -include (dirname(__FILE__) . '/resource.php'); + + * @package group + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->group->common = '權限分組'; +$lang->group->browse = '瀏覽分組'; +$lang->group->create = '新增分組'; +$lang->group->edit = '編輯分組'; +$lang->group->copy = '複製分組'; +$lang->group->delete = '刪除分組'; +$lang->group->managePriv = '權限維護'; +$lang->group->managePrivByGroup = '權限維護'; +$lang->group->managePrivByModule = '按模組分配權限'; +$lang->group->manageMember = '成員維護'; +$lang->group->linkMember = '關聯用戶'; +$lang->group->unlinkMember = '移除用戶'; +$lang->group->confirmDelete = '您確定刪除該用戶分組嗎?'; +$lang->group->successSaved = '成功保存'; +$lang->group->errorNotSaved = '沒有保存,請確認選擇了權限數據。'; + +$lang->group->id = '編號'; +$lang->group->name = '分組名稱'; +$lang->group->desc = '分組描述'; +$lang->group->users = '用戶列表'; +$lang->group->module = '模組'; +$lang->group->method = '方法'; +$lang->group->priv = '權限'; +$lang->group->checkall = '全選'; +$lang->group->option = '選項'; +$lang->group->inside = '組內用戶'; +$lang->group->outside = '組外用戶'; + +$lang->group->copyOptions['copyPriv'] = '複製權限'; +$lang->group->copyOptions['copyUser'] = '複製用戶'; + +$lang->group->versions[''] = '顯示各版本新增權限'; +$lang->group->versions['3.0.beta1'] = '禪道3.0.beta1'; +$lang->group->versions['2.4'] = '禪道2.4'; +$lang->group->versions['2.3'] = '禪道2.3'; +$lang->group->versions['2.2'] = '禪道2.2'; +$lang->group->versions['2.1'] = '禪道2.1'; +$lang->group->versions['2.0'] = '禪道2.0'; +$lang->group->versions['1.5'] = '禪道1.5'; +$lang->group->versions['1.4'] = '禪道1.4'; +$lang->group->versions['1.3'] = '禪道1.3'; +$lang->group->versions['1.2'] = '禪道1.2'; +$lang->group->versions['1.1'] = '禪道1.1'; +$lang->group->versions['1.0.1'] = '禪道1.0.1'; + +include (dirname(__FILE__) . '/resource.php'); diff --git a/module/group/model.php b/module/group/model.php index 7f50c4772d..9eac983dd0 100644 --- a/module/group/model.php +++ b/module/group/model.php @@ -1,251 +1,251 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> -specialChars('name, desc')->get(); - return $this->dao->insert(TABLE_GROUP)->data($group)->batchCheck($this->config->group->create->requiredFields, 'notempty')->exec(); - } - - /** - * Update a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function update($groupID) - { - $group = fixer::input('post')->specialChars('name, desc')->get(); - return $this->dao->update(TABLE_GROUP)->data($group)->batchCheck($this->config->group->edit->requiredFields, 'notempty')->where('id')->eq($groupID)->exec(); - } - - /** - * Copy a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function copy($groupID) - { - $group = fixer::input('post')->specialChars('name, desc')->remove('options')->get(); - $this->dao->insert(TABLE_GROUP)->data($group)->check('name', 'unique')->check('name', 'notempty')->exec(); - if($this->post->options == false) return; - if(!dao::isError()) - { - $newGroupID = $this->dao->lastInsertID(); - $options = join(',', $this->post->options); - if(strpos($options, 'copyPriv') !== false) $this->copyPriv($groupID, $newGroupID); - if(strpos($options, 'copyUser') !== false) $this->copyUser($groupID, $newGroupID); - } - } - - /** - * Copy privileges. - * - * @param string $fromGroup - * @param string $toGroup - * @access public - * @return void - */ - public function copyPriv($fromGroup, $toGroup) - { - $privs = $this->dao->findByGroup($fromGroup)->from(TABLE_GROUPPRIV)->fetchAll(); - foreach($privs as $priv) - { - $priv->group = $toGroup; - $this->dao->insert(TABLE_GROUPPRIV)->data($priv)->exec(); - } - } - - /** - * Copy user. - * - * @param string $fromGroup - * @param string $toGroup - * @access public - * @return void - */ - public function copyUser($fromGroup, $toGroup) - { - $users = $this->dao->findByGroup($fromGroup)->from(TABLE_USERGROUP)->fetchAll(); - foreach($users as $user) - { - $user->group = $toGroup; - $this->dao->insert(TABLE_USERGROUP)->data($user)->exec(); - } - } - - /** - * Get group lists. - * - * @param int $companyID - * @access public - * @return array - */ - public function getList($companyID) - { - return $this->dao->findByCompany($companyID)->from(TABLE_GROUP)->fetchAll(); - } - - /** - * Get group pairs. - * - * @access public - * @return array - */ - public function getPairs() - { - return $this->dao->findByCompany($this->app->company->id)->fields('id, name')->from(TABLE_GROUP)->fetchPairs(); - } - - /** - * Get group by id. - * - * @param int $groupID - * @access public - * @return object - */ - public function getByID($groupID) - { - return $this->dao->findById($groupID)->from(TABLE_GROUP)->fetch(); - } - - /** - * Get privileges of a groups. - * - * @param int $groupID - * @access public - * @return array - */ - public function getPrivs($groupID) - { - $privs = array(); - $stmt = $this->dao->select('module, method')->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->orderBy('module')->query(); - while($priv = $stmt->fetch()) $privs[$priv->module][$priv->method] = $priv->method; - return $privs; - } - - /** - * Get user pairs of a group. - * - * @param int $groupID - * @access public - * @return array - */ - public function getUserPairs($groupID) - { - return $this->dao->select('t2.account, t2.realname') - ->from(TABLE_USERGROUP)->alias('t1') - ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') - ->where('`group`')->eq((int)$groupID) - ->andWhere('t2.deleted')->eq(0) - ->andWhere('t2.company')->eq($this->app->company->id) - ->orderBy('t2.account') - ->fetchPairs(); - } - - /** - * Delete a group. - * - * @param int $groupID - * @access public - * @return void - */ - public function delete($groupID) - { - $this->dao->delete()->from(TABLE_GROUP)->where('id')->eq($groupID)->exec(); - $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->exec(); - $this->dao->delete()->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->exec(); - } - - /** - * Update privilege of a group. - * - * @param int $groupID - * @access public - * @return bool - */ - public function updatePrivByGroup($groupID) - { - /* Delete old. */ - $this->dao->delete()->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->exec(); - - /* Insert new. */ - foreach($this->post->actions as $moduleName => $moduleActions) - { - foreach($moduleActions as $actionName) - { - $data->group = $groupID; - $data->module = $moduleName; - $data->method = $actionName; - $this->dao->insert(TABLE_GROUPPRIV)->data($data)->exec(); - } - } - return true; - } - - /** - * Update privilege by module. - * - * @access public - * @return void - */ - public function updatePrivByModule() - { - if($this->post->module == false or $this->post->actions == false or $this->post->groups == false) return false; - - foreach($this->post->actions as $action) - { - foreach($this->post->groups as $group) - { - $data->group = $group; - $data->module = $this->post->module; - $data->method = $action; - $this->dao->replace(TABLE_GROUPPRIV)->data($data)->exec(); - } - } - return true; - } - - /** - * Update users. - * - * @param int $groupID - * @access public - * @return void - */ - public function updateUser($groupID) - { - /* Delete old. */ - $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->exec(); - - /* Insert new. */ - if($this->post->members == false) return; - foreach($this->post->members as $account) - { - $data->account = $account; - $data->group = $groupID; - $this->dao->insert(TABLE_USERGROUP)->data($data)->exec(); - } - } -} + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> +specialChars('name, desc')->get(); + return $this->dao->insert(TABLE_GROUP)->data($group)->batchCheck($this->config->group->create->requiredFields, 'notempty')->exec(); + } + + /** + * Update a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function update($groupID) + { + $group = fixer::input('post')->specialChars('name, desc')->get(); + return $this->dao->update(TABLE_GROUP)->data($group)->batchCheck($this->config->group->edit->requiredFields, 'notempty')->where('id')->eq($groupID)->exec(); + } + + /** + * Copy a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function copy($groupID) + { + $group = fixer::input('post')->specialChars('name, desc')->remove('options')->get(); + $this->dao->insert(TABLE_GROUP)->data($group)->check('name', 'unique')->check('name', 'notempty')->exec(); + if($this->post->options == false) return; + if(!dao::isError()) + { + $newGroupID = $this->dao->lastInsertID(); + $options = join(',', $this->post->options); + if(strpos($options, 'copyPriv') !== false) $this->copyPriv($groupID, $newGroupID); + if(strpos($options, 'copyUser') !== false) $this->copyUser($groupID, $newGroupID); + } + } + + /** + * Copy privileges. + * + * @param string $fromGroup + * @param string $toGroup + * @access public + * @return void + */ + public function copyPriv($fromGroup, $toGroup) + { + $privs = $this->dao->findByGroup($fromGroup)->from(TABLE_GROUPPRIV)->fetchAll(); + foreach($privs as $priv) + { + $priv->group = $toGroup; + $this->dao->insert(TABLE_GROUPPRIV)->data($priv)->exec(); + } + } + + /** + * Copy user. + * + * @param string $fromGroup + * @param string $toGroup + * @access public + * @return void + */ + public function copyUser($fromGroup, $toGroup) + { + $users = $this->dao->findByGroup($fromGroup)->from(TABLE_USERGROUP)->fetchAll(); + foreach($users as $user) + { + $user->group = $toGroup; + $this->dao->insert(TABLE_USERGROUP)->data($user)->exec(); + } + } + + /** + * Get group lists. + * + * @param int $companyID + * @access public + * @return array + */ + public function getList($companyID) + { + return $this->dao->findByCompany($companyID)->from(TABLE_GROUP)->fetchAll(); + } + + /** + * Get group pairs. + * + * @access public + * @return array + */ + public function getPairs() + { + return $this->dao->findByCompany($this->app->company->id)->fields('id, name')->from(TABLE_GROUP)->fetchPairs(); + } + + /** + * Get group by id. + * + * @param int $groupID + * @access public + * @return object + */ + public function getByID($groupID) + { + return $this->dao->findById($groupID)->from(TABLE_GROUP)->fetch(); + } + + /** + * Get privileges of a groups. + * + * @param int $groupID + * @access public + * @return array + */ + public function getPrivs($groupID) + { + $privs = array(); + $stmt = $this->dao->select('module, method')->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->orderBy('module')->query(); + while($priv = $stmt->fetch()) $privs[$priv->module][$priv->method] = $priv->method; + return $privs; + } + + /** + * Get user pairs of a group. + * + * @param int $groupID + * @access public + * @return array + */ + public function getUserPairs($groupID) + { + return $this->dao->select('t2.account, t2.realname') + ->from(TABLE_USERGROUP)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') + ->where('`group`')->eq((int)$groupID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t2.company')->eq($this->app->company->id) + ->orderBy('t2.account') + ->fetchPairs(); + } + + /** + * Delete a group. + * + * @param int $groupID + * @access public + * @return void + */ + public function delete($groupID) + { + $this->dao->delete()->from(TABLE_GROUP)->where('id')->eq($groupID)->exec(); + $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->exec(); + $this->dao->delete()->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->exec(); + } + + /** + * Update privilege of a group. + * + * @param int $groupID + * @access public + * @return bool + */ + public function updatePrivByGroup($groupID) + { + /* Delete old. */ + $this->dao->delete()->from(TABLE_GROUPPRIV)->where('`group`')->eq($groupID)->exec(); + + /* Insert new. */ + foreach($this->post->actions as $moduleName => $moduleActions) + { + foreach($moduleActions as $actionName) + { + $data->group = $groupID; + $data->module = $moduleName; + $data->method = $actionName; + $this->dao->insert(TABLE_GROUPPRIV)->data($data)->exec(); + } + } + return true; + } + + /** + * Update privilege by module. + * + * @access public + * @return void + */ + public function updatePrivByModule() + { + if($this->post->module == false or $this->post->actions == false or $this->post->groups == false) return false; + + foreach($this->post->actions as $action) + { + foreach($this->post->groups as $group) + { + $data->group = $group; + $data->module = $this->post->module; + $data->method = $action; + $this->dao->replace(TABLE_GROUPPRIV)->data($data)->exec(); + } + } + return true; + } + + /** + * Update users. + * + * @param int $groupID + * @access public + * @return void + */ + public function updateUser($groupID) + { + /* Delete old. */ + $this->dao->delete()->from(TABLE_USERGROUP)->where('`group`')->eq($groupID)->exec(); + + /* Insert new. */ + if($this->post->members == false) return; + foreach($this->post->members as $account) + { + $data->account = $account; + $data->group = $groupID; + $this->dao->insert(TABLE_USERGROUP)->data($data)->exec(); + } + } +} diff --git a/module/group/view/browse.html.php b/module/group/view/browse.html.php index fd325a9b1e..c43492294d 100644 --- a/module/group/view/browse.html.php +++ b/module/group/view/browse.html.php @@ -1,50 +1,50 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          group->browse;?>
          -
          group->create);?>
          -
          group->id;?>group->name;?>group->desc;?>group->users;?>actions;?>
          id;?>name;?>desc;?>id] as $user) echo "$user";?> - id", $lang->group->managePrivByGroup);?> - id", $lang->group->manageMember);?> - id", $lang->edit);?> - id", $lang->copy);?> - id", $lang->delete, "hiddenwin");?> -
          group->managePrivByModule, inlink('managePriv', 'type=byModule'));?>
          - + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          group->browse;?>
          +
          group->create);?>
          +
          group->id;?>group->name;?>group->desc;?>group->users;?>actions;?>
          id;?>name;?>desc;?>id] as $user) echo "$user";?> + id", $lang->group->managePrivByGroup);?> + id", $lang->group->manageMember);?> + id", $lang->edit);?> + id", $lang->copy);?> + id", $lang->delete, "hiddenwin");?> +
          group->managePrivByModule, inlink('managePriv', 'type=byModule'));?>
          + diff --git a/module/group/view/copy.html.php b/module/group/view/copy.html.php index 553892a363..7d1d5d03d4 100644 --- a/module/group/view/copy.html.php +++ b/module/group/view/copy.html.php @@ -1,32 +1,32 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - - -
          group->copy;?>
          group->name;?>name, "class='text-1'");?>
          group->desc;?>desc, "rows='5' class='area-1'");?>
          group->option;?>group->copyOptions);?>
          -
          - + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + + +
          group->copy;?>
          group->name;?>name, "class='text-1'");?>
          group->desc;?>desc, "rows='5' class='area-1'");?>
          group->option;?>group->copyOptions);?>
          +
          + diff --git a/module/group/view/create.html.php b/module/group/view/create.html.php index c049270002..c6753537fb 100644 --- a/module/group/view/create.html.php +++ b/module/group/view/create.html.php @@ -1,28 +1,28 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - -
          group->create;?>
          group->name;?>
          group->desc;?>
          -
          - + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + +
          group->create;?>
          group->name;?>
          group->desc;?>
          +
          + diff --git a/module/group/view/edit.html.php b/module/group/view/edit.html.php index 88dfbae365..53bdca0076 100644 --- a/module/group/view/edit.html.php +++ b/module/group/view/edit.html.php @@ -1,28 +1,28 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - -
          group->edit;?>
          group->name;?>name, "class='text-1'");?>
          group->desc;?>desc, "rows='5' class='area-1'");?>
          -
          - + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + +
          group->edit;?>
          group->name;?>name, "class='text-1'");?>
          group->desc;?>desc, "rows='5' class='area-1'");?>
          +
          + diff --git a/module/group/view/managemember.html.php b/module/group/view/managemember.html.php index b0c75001f7..08e216091d 100644 --- a/module/group/view/managemember.html.php +++ b/module/group/view/managemember.html.php @@ -1,47 +1,47 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - -
          name . $lang->colon . $lang->group->manageMember;?>
          group->inside;?> - $realname):?> -
          ' . html::checkbox('members', array($account => $realname), $account) . '';?>
          - "; $i ++;?> - -
          group->outside;?> - $realname):?> -
          ' . html::checkbox('members', array($account => $realname), '') . '';?>
          - "; $i ++;?> - -
          - goback, $this->createLink('group', 'browse')); - echo html::hidden('foo'); // Just a var, to make sure $_POST is not empty. - ?> -
          -
          - + + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + +
          name . $lang->colon . $lang->group->manageMember;?>
          group->inside;?> + $realname):?> +
          ' . html::checkbox('members', array($account => $realname), $account) . '';?>
          + "; $i ++;?> + +
          group->outside;?> + $realname):?> +
          ' . html::checkbox('members', array($account => $realname), '') . '';?>
          + "; $i ++;?> + +
          + goback, $this->createLink('group', 'browse')); + echo html::hidden('foo'); // Just a var, to make sure $_POST is not empty. + ?> +
          +
          + diff --git a/module/group/view/managepriv.html.php b/module/group/view/managepriv.html.php index 33240ca990..057cc326bb 100644 --- a/module/group/view/managepriv.html.php +++ b/module/group/view/managepriv.html.php @@ -1,17 +1,17 @@ - - * @package group - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + * @package group + * @version $Id$ + * @link http://www.zentao.net + */ +?> + - * @package group - * @version $Id: managepriv.html.php 1517 2011-03-07 10:02:57Z wwccss $ - * @link http://www.zentao.net - */ -?> -
          - - - - - - - resource as $moduleName => $moduleActions):?> - '> - - - - - - - -
          name . $lang->colon . $lang->group->managePriv;?> - - lang->group->versions, '', "onchange=showPriv(this.value)"); - ?> - -
          group->module;?>group->method;?>
          lang->$moduleName->common;?> - - - $actionLabel):?> -
          - /> - >$moduleName->$actionLabel;?> -
          - "; $i ++;?> - -
          group->checkall;?> - save); - echo html::linkButton($lang->goback, $this->createLink('group', 'browse')); - echo html::hidden('foo'); // Just a hidden var, to make sure $_POST is not empty. - ?> -
          -
          - + + * @package group + * @version $Id: managepriv.html.php 1517 2011-03-07 10:02:57Z wwccss $ + * @link http://www.zentao.net + */ +?> +
          + + + + + + + resource as $moduleName => $moduleActions):?> + '> + + + + + + + +
          name . $lang->colon . $lang->group->managePriv;?> + + lang->group->versions, '', "onchange=showPriv(this.value)"); + ?> + +
          group->module;?>group->method;?>
          lang->$moduleName->common;?> + + + $actionLabel):?> +
          + /> + >$moduleName->$actionLabel;?> +
          + "; $i ++;?> + +
          group->checkall;?> + save); + echo html::linkButton($lang->goback, $this->createLink('group', 'browse')); + echo html::hidden('foo'); // Just a hidden var, to make sure $_POST is not empty. + ?> +
          +
          + diff --git a/module/group/view/privbymodule.html.php b/module/group/view/privbymodule.html.php index 89030c1b89..87de1d036c 100644 --- a/module/group/view/privbymodule.html.php +++ b/module/group/view/privbymodule.html.php @@ -1,45 +1,45 @@ - - * @package group - * @version $Id: managepriv.html.php 1517 2011-03-07 10:02:57Z wwccss $ - * @link http://www.zentao.net - */ -?> -
          - - - - - - - - - - - - - - - -
          group->managePriv;?>
          group->module;?>group->method;?>group->common;?>
          - $moduleActions) - { - echo html::select('actions[]', $moduleActions, '', "multiple='multiple' class='$class {$module}Actions'"); - $class = 'hidden'; - } - ?> -
          - save); - echo html::linkButton($lang->goback, $this->createLink('group', 'browse')); - echo html::hidden('foo'); // Just make $_POST not empty.. - ?> -
          -
          + + * @package group + * @version $Id: managepriv.html.php 1517 2011-03-07 10:02:57Z wwccss $ + * @link http://www.zentao.net + */ +?> +
          + + + + + + + + + + + + + + + +
          group->managePriv;?>
          group->module;?>group->method;?>group->common;?>
          + $moduleActions) + { + echo html::select('actions[]', $moduleActions, '', "multiple='multiple' class='$class {$module}Actions'"); + $class = 'hidden'; + } + ?> +
          + save); + echo html::linkButton($lang->goback, $this->createLink('group', 'browse')); + echo html::hidden('foo'); // Just make $_POST not empty.. + ?> +
          +
          diff --git a/module/help/control.php b/module/help/control.php index 8232219f31..2b25a20c30 100644 --- a/module/help/control.php +++ b/module/help/control.php @@ -1,46 +1,46 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -class help extends control -{ - /** - * Get the help info of a field.. - * - * @param string $module - * @param string $method - * @param string $field - * @param string $clientLang - * @access public - * @return void - */ - public function field($module, $method, $field) - { - $clientLang = $this->app->getClientLang(); - include "./lang/field.$clientLang.php"; - - $fieldName = ''; - $fieldNote = $this->lang->help->noHelpYet; - if(isset($help->$module->$field)) - { - $fieldHelp = explode('|', $help->$module->$field); - $fieldName = $fieldHelp[0]; - if(isset($fieldHelp[1])) $fieldNote = $fieldHelp[1]; - } - elseif($field == 'labels') - { - list($fieldName, $fieldNote) = explode('|', $help->file->labels); - } - $this->view->header->title = $fieldName; - $this->view->fieldName = $fieldName; - $this->view->fieldNote = $fieldNote; - $this->display(); - } -} + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +class help extends control +{ + /** + * Get the help info of a field.. + * + * @param string $module + * @param string $method + * @param string $field + * @param string $clientLang + * @access public + * @return void + */ + public function field($module, $method, $field) + { + $clientLang = $this->app->getClientLang(); + include "./lang/field.$clientLang.php"; + + $fieldName = ''; + $fieldNote = $this->lang->help->noHelpYet; + if(isset($help->$module->$field)) + { + $fieldHelp = explode('|', $help->$module->$field); + $fieldName = $fieldHelp[0]; + if(isset($fieldHelp[1])) $fieldNote = $fieldHelp[1]; + } + elseif($field == 'labels') + { + list($fieldName, $fieldNote) = explode('|', $help->file->labels); + } + $this->view->header->title = $fieldName; + $this->view->fieldName = $fieldName; + $this->view->fieldNote = $fieldNote; + $this->display(); + } +} diff --git a/module/help/model.php b/module/help/model.php index 2bda8b8238..8947a3c3b1 100644 --- a/module/help/model.php +++ b/module/help/model.php @@ -1,15 +1,15 @@ - - * @package help - * @version $Id$ - * @link http://www.zentao.net - */ -class helpModel extends model -{ -} - + + * @package help + * @version $Id$ + * @link http://www.zentao.net + */ +class helpModel extends model +{ +} + diff --git a/module/help/view/field.html.php b/module/help/view/field.html.php index fd95904a08..c54f51fdf2 100644 --- a/module/help/view/field.html.php +++ b/module/help/view/field.html.php @@ -1,19 +1,19 @@ - - * @package help - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          ' . $fieldName . '' . ($fieldName ? $lang->arrow : '') . $fieldNote?>
          - + * @package help + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          ' . $fieldName . '' . ($fieldName ? $lang->arrow : '') . $fieldNote?>
          + - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -class index extends control -{ - /** - * Construct function, load project, product. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - } - - /** - * The index page of whole zentao system. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('my', 'index')); - } - - /** - * Just test the extension engine. - * - * @access public - * @return void - */ - public function testext() - { - echo $this->fetch('misc', 'getsid'); - } -} + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +class index extends control +{ + /** + * Construct function, load project, product. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + /** + * The index page of whole zentao system. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('my', 'index')); + } + + /** + * Just test the extension engine. + * + * @access public + * @return void + */ + public function testext() + { + echo $this->fetch('misc', 'getsid'); + } +} diff --git a/module/index/model.php b/module/index/model.php index f934a1bd0a..2afcac9a23 100644 --- a/module/index/model.php +++ b/module/index/model.php @@ -1,15 +1,15 @@ - - * @package index - * @version $Id$ - */ -?> - + * @package index + * @version $Id$ + */ +?> + - * @package install - * @version $Id$ - * @link http://www.zentao.net - */ -class install extends control -{ - /** - * Construct function. - * - * @access public - * @return void - */ - public function __construct() - { - if(!defined('IN_INSTALL')) die(); - parent::__construct(); - $this->loadModel('admin'); - $this->loadModel('user'); - $this->config->webRoot = $this->install->getWebRoot(); - } - - /** - * Index page of install module. - * - * @access public - * @return void - */ - public function index() - { - if(!isset($this->config->installed) or !$this->config->installed) $this->session->set('installing', true); - - $this->view->header->title = $this->lang->install->welcome; - - if($release = $this->install->getLatestRelease()) $this->view->latestRelease = $release; - - $this->display(); - } - - /** - * Check the system. - * - * @access public - * @return void - */ - public function step1() - { - $this->view->header->title = $this->lang->install->checking; - $this->view->phpVersion = $this->install->getPhpVersion(); - $this->view->phpResult = $this->install->checkPHP(); - $this->view->pdoResult = $this->install->checkPDO(); - $this->view->pdoMySQLResult = $this->install->checkPDOMySQL(); - $this->view->jsonResult = $this->install->checkJSON(); - $this->view->tmpRootInfo = $this->install->getTmpRoot(); - $this->view->tmpRootResult = $this->install->checkTmpRoot(); - $this->view->dataRootInfo = $this->install->getDataRoot(); - $this->view->dataRootResult = $this->install->checkDataRoot(); - $this->view->iniInfo = $this->install->getIniInfo(); - $this->display(); - } - - /** - * Set configs. - * - * @access public - * @return void - */ - public function step2() - { - $this->view->header->title = $this->lang->install->setConfig; - $this->display(); - } - - /** - * Create the config file. - * - * @access public - * @return void - */ - public function step3() - { - if(!empty($_POST)) - { - $return = $this->install->checkConfig(); - if($return->result == 'ok') - { - $this->view = (object)$_POST; - $this->view->app = $this->app; - $this->view->lang = $this->lang; - $this->view->config = $this->config; - $this->view->domain = $this->server->HTTP_HOST; - $this->view->header->title = $this->lang->install->saveConfig; - $this->display(); - } - else - { - $this->view->header->title = $this->lang->install->saveConfig; - $this->view->error = $return->error; - $this->display(); - } - } - else - { - $this->locate($this->createLink('install')); - } - } - - /** - * Create company, admin. - * - * @access public - * @return void - */ - public function step4() - { - if(!empty($_POST)) - { - $this->session->set('account', $this->post->account); - $this->install->grantPriv(); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('setting')->updateVersion($this->config->version); - $this->setting->setSN(); - die(js::locate(inlink('step5'), 'parent')); - } - - $this->view->header->title = $this->lang->install->getPriv; - if(!isset($this->config->installed) or !$this->config->installed) - { - $this->view->error = $this->lang->install->errorNotSaveConfig; - $this->display(); - } - else - { - $this->view->pmsDomain = $this->server->HTTP_HOST; - $this->display(); - } - } - - /** - * Join zentao community or login pms. - * - * @access public - * @return void - */ - public function step5() - { - $this->display(); - } - - /** - * Register zentao. - * - * @access public - * @return void - */ - public function register() - { - if($_POST) - { - $this->app->user->account = $this->session->account; - $response = $this->admin->registerByAPI(); - if($response == 'success') - { - unset($_SESSION['installing']); - session_destroy(); - die(js::locate('index.php', 'parent')); - } - } - $this->view->sn = $this->admin->getSN(); - $this->display(); - } - - /** - * Login zentao. - * - * @access public - * @return void - */ - public function login() - { - if($_POST) - { - $this->app->user->account = $this->session->account; - $response = $this->admin->loginByAPI(); - if($response == 'success') - { - unset($_SESSION['installing']); - session_destroy(); - die(js::locate('index.php', 'parent')); - } - } - $this->view->sn = $this->admin->getSN(); - $this->display(); - } -} + + * @package install + * @version $Id$ + * @link http://www.zentao.net + */ +class install extends control +{ + /** + * Construct function. + * + * @access public + * @return void + */ + public function __construct() + { + if(!defined('IN_INSTALL')) die(); + parent::__construct(); + $this->loadModel('admin'); + $this->loadModel('user'); + $this->config->webRoot = $this->install->getWebRoot(); + } + + /** + * Index page of install module. + * + * @access public + * @return void + */ + public function index() + { + if(!isset($this->config->installed) or !$this->config->installed) $this->session->set('installing', true); + + $this->view->header->title = $this->lang->install->welcome; + + if($release = $this->install->getLatestRelease()) $this->view->latestRelease = $release; + + $this->display(); + } + + /** + * Check the system. + * + * @access public + * @return void + */ + public function step1() + { + $this->view->header->title = $this->lang->install->checking; + $this->view->phpVersion = $this->install->getPhpVersion(); + $this->view->phpResult = $this->install->checkPHP(); + $this->view->pdoResult = $this->install->checkPDO(); + $this->view->pdoMySQLResult = $this->install->checkPDOMySQL(); + $this->view->jsonResult = $this->install->checkJSON(); + $this->view->tmpRootInfo = $this->install->getTmpRoot(); + $this->view->tmpRootResult = $this->install->checkTmpRoot(); + $this->view->dataRootInfo = $this->install->getDataRoot(); + $this->view->dataRootResult = $this->install->checkDataRoot(); + $this->view->iniInfo = $this->install->getIniInfo(); + $this->display(); + } + + /** + * Set configs. + * + * @access public + * @return void + */ + public function step2() + { + $this->view->header->title = $this->lang->install->setConfig; + $this->display(); + } + + /** + * Create the config file. + * + * @access public + * @return void + */ + public function step3() + { + if(!empty($_POST)) + { + $return = $this->install->checkConfig(); + if($return->result == 'ok') + { + $this->view = (object)$_POST; + $this->view->app = $this->app; + $this->view->lang = $this->lang; + $this->view->config = $this->config; + $this->view->domain = $this->server->HTTP_HOST; + $this->view->header->title = $this->lang->install->saveConfig; + $this->display(); + } + else + { + $this->view->header->title = $this->lang->install->saveConfig; + $this->view->error = $return->error; + $this->display(); + } + } + else + { + $this->locate($this->createLink('install')); + } + } + + /** + * Create company, admin. + * + * @access public + * @return void + */ + public function step4() + { + if(!empty($_POST)) + { + $this->session->set('account', $this->post->account); + $this->install->grantPriv(); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('setting')->updateVersion($this->config->version); + $this->setting->setSN(); + die(js::locate(inlink('step5'), 'parent')); + } + + $this->view->header->title = $this->lang->install->getPriv; + if(!isset($this->config->installed) or !$this->config->installed) + { + $this->view->error = $this->lang->install->errorNotSaveConfig; + $this->display(); + } + else + { + $this->view->pmsDomain = $this->server->HTTP_HOST; + $this->display(); + } + } + + /** + * Join zentao community or login pms. + * + * @access public + * @return void + */ + public function step5() + { + $this->display(); + } + + /** + * Register zentao. + * + * @access public + * @return void + */ + public function register() + { + if($_POST) + { + $this->app->user->account = $this->session->account; + $response = $this->admin->registerByAPI(); + if($response == 'success') + { + unset($_SESSION['installing']); + session_destroy(); + die(js::locate('index.php', 'parent')); + } + } + $this->view->sn = $this->admin->getSN(); + $this->display(); + } + + /** + * Login zentao. + * + * @access public + * @return void + */ + public function login() + { + if($_POST) + { + $this->app->user->account = $this->session->account; + $response = $this->admin->loginByAPI(); + if($response == 'success') + { + unset($_SESSION['installing']); + session_destroy(); + die(js::locate('index.php', 'parent')); + } + } + $this->view->sn = $this->admin->getSN(); + $this->display(); + } +} diff --git a/module/install/lang/en.php b/module/install/lang/en.php index 0fd33ae1f8..f2ada2a8e1 100644 --- a/module/install/lang/en.php +++ b/module/install/lang/en.php @@ -1,113 +1,113 @@ - - * @package install - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->install->common = 'Install'; -$lang->install->next = 'Next'; -$lang->install->pre = 'Back'; -$lang->install->reload = 'Reload'; -$lang->install->error = 'Error '; - -$lang->install->start = 'Start install'; -$lang->install->keepInstalling = 'Keep install this version'; -$lang->install->seeLatestRelease = 'See the latest release.'; -$lang->install->welcome = 'Welcome to use ZenTaoPMS.'; -$lang->install->desc = <<Nature EasySoft Network Tecnology Co.ltd, QingDao, China。 -The official website of ZenTaoPMS is http://en.zentao.net -twitter:zentaopms - -The version of current release is %s。 -EOT; - - - -$lang->install->newReleased= "Notice:There is a new version %s, released on %s。"; -$lang->install->choice = 'You can '; -$lang->install->checking = 'System checking'; -$lang->install->ok = 'OK(√)'; -$lang->install->fail = 'Failed(×)'; -$lang->install->loaded = 'Loaded'; -$lang->install->unloaded = 'Not loaded'; -$lang->install->exists = 'Exists '; -$lang->install->notExists = 'Not exists '; -$lang->install->writable = 'Writable '; -$lang->install->notWritable= 'Not writable '; -$lang->install->phpINI = 'PHP ini file'; -$lang->install->checkItem = 'Items'; -$lang->install->current = 'Current'; -$lang->install->result = 'Result'; -$lang->install->action = 'How to fix'; - -$lang->install->phpVersion = 'PHP version'; -$lang->install->phpFail = 'Must > 5.2.0'; - -$lang->install->pdo = 'PDO extension'; -$lang->install->pdoFail = 'Edit the php.ini file to load PDO extsion.'; -$lang->install->pdoMySQL = 'PDO_MySQL extension'; -$lang->install->pdoMySQLFail = 'Edit the php.ini file to load PDO_MySQL extsion.'; -$lang->install->json = 'JSON extension'; -$lang->install->jsonFail = 'Edit the php.ini file to load JSON extension'; -$lang->install->tmpRoot = 'Temp directory'; -$lang->install->dataRoot = 'Upload directory.'; -$lang->install->mkdir = '

          Should creat the directory %s。
          Under linux, can try
          mkdir -p %s

          '; -$lang->install->chmod = 'Should change the permission of "%s".
          Under linux, can try
          chmod o=rwx -R %s'; - -$lang->install->settingDB = 'Set database'; -$lang->install->webRoot = 'ZenTaoPMS path'; -$lang->install->requestType = 'URL type'; -$lang->install->defaultLang = 'Default Language'; -$lang->install->dbHost = 'Database host'; -$lang->install->dbHostNote = 'If localhost can not connect, try 127.0.0.1'; -$lang->install->dbPort = 'Host port'; -$lang->install->dbUser = 'Database user'; -$lang->install->dbPassword = 'Database password'; -$lang->install->dbName = 'Database name'; -$lang->install->dbPrefix = 'Table prefix'; -$lang->install->createDB = 'Auto create database'; -$lang->install->clearDB = 'Clear data if database exists.'; - -$lang->install->requestTypes['GET'] = 'GET'; -$lang->install->requestTypes['PATH_INFO'] = 'PATH_INFO'; - -$lang->install->errorConnectDB = 'Database connect failed.'; -$lang->install->errorCreateDB = 'Database create failed.'; -$lang->install->errorDBExists = 'Database alread exists, to continue install, check the clear db box.'; -$lang->install->errorCreateTable = 'Table create failed.'; - -$lang->install->setConfig = 'Create config file'; -$lang->install->key = 'Item'; -$lang->install->value = 'Value'; -$lang->install->saveConfig = 'Save config'; -$lang->install->save2File = '
          Try to save the config auto, but failed.
          Copy the text of the textareaand save to " %s ".'; -$lang->install->saved2File = 'The config file has saved to "%s ".'; -$lang->install->errorNotSaveConfig = "Hasn't save the config file. "; - -$lang->install->getPriv = 'Set admin'; -$lang->install->company = 'Company name'; -$lang->install->pms = 'ZenTaoPMS domain'; -$lang->install->pmsNote = 'The domain name or ip address of ZenTaoPMS, no http://'; -$lang->install->account = 'Administrator'; -$lang->install->password = 'Admin password'; -$lang->install->errorEmptyPassword = "Can't be empty"; - -$lang->install->success = "Success installed"; - -$lang->install->joinZentao = <<Please remove install.php in time。Now, you can: - -Register or login into Zetao community, feed back and get support. - -Login into ZenTaoPMS, create groups and grant priviledges. -EOT; + + * @package install + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->install->common = 'Install'; +$lang->install->next = 'Next'; +$lang->install->pre = 'Back'; +$lang->install->reload = 'Reload'; +$lang->install->error = 'Error '; + +$lang->install->start = 'Start install'; +$lang->install->keepInstalling = 'Keep install this version'; +$lang->install->seeLatestRelease = 'See the latest release.'; +$lang->install->welcome = 'Welcome to use ZenTaoPMS.'; +$lang->install->desc = <<Nature EasySoft Network Tecnology Co.ltd, QingDao, China。 +The official website of ZenTaoPMS is http://en.zentao.net +twitter:zentaopms + +The version of current release is %s。 +EOT; + + + +$lang->install->newReleased= "Notice:There is a new version %s, released on %s。"; +$lang->install->choice = 'You can '; +$lang->install->checking = 'System checking'; +$lang->install->ok = 'OK(√)'; +$lang->install->fail = 'Failed(×)'; +$lang->install->loaded = 'Loaded'; +$lang->install->unloaded = 'Not loaded'; +$lang->install->exists = 'Exists '; +$lang->install->notExists = 'Not exists '; +$lang->install->writable = 'Writable '; +$lang->install->notWritable= 'Not writable '; +$lang->install->phpINI = 'PHP ini file'; +$lang->install->checkItem = 'Items'; +$lang->install->current = 'Current'; +$lang->install->result = 'Result'; +$lang->install->action = 'How to fix'; + +$lang->install->phpVersion = 'PHP version'; +$lang->install->phpFail = 'Must > 5.2.0'; + +$lang->install->pdo = 'PDO extension'; +$lang->install->pdoFail = 'Edit the php.ini file to load PDO extsion.'; +$lang->install->pdoMySQL = 'PDO_MySQL extension'; +$lang->install->pdoMySQLFail = 'Edit the php.ini file to load PDO_MySQL extsion.'; +$lang->install->json = 'JSON extension'; +$lang->install->jsonFail = 'Edit the php.ini file to load JSON extension'; +$lang->install->tmpRoot = 'Temp directory'; +$lang->install->dataRoot = 'Upload directory.'; +$lang->install->mkdir = '

          Should creat the directory %s。
          Under linux, can try
          mkdir -p %s

          '; +$lang->install->chmod = 'Should change the permission of "%s".
          Under linux, can try
          chmod o=rwx -R %s'; + +$lang->install->settingDB = 'Set database'; +$lang->install->webRoot = 'ZenTaoPMS path'; +$lang->install->requestType = 'URL type'; +$lang->install->defaultLang = 'Default Language'; +$lang->install->dbHost = 'Database host'; +$lang->install->dbHostNote = 'If localhost can not connect, try 127.0.0.1'; +$lang->install->dbPort = 'Host port'; +$lang->install->dbUser = 'Database user'; +$lang->install->dbPassword = 'Database password'; +$lang->install->dbName = 'Database name'; +$lang->install->dbPrefix = 'Table prefix'; +$lang->install->createDB = 'Auto create database'; +$lang->install->clearDB = 'Clear data if database exists.'; + +$lang->install->requestTypes['GET'] = 'GET'; +$lang->install->requestTypes['PATH_INFO'] = 'PATH_INFO'; + +$lang->install->errorConnectDB = 'Database connect failed.'; +$lang->install->errorCreateDB = 'Database create failed.'; +$lang->install->errorDBExists = 'Database alread exists, to continue install, check the clear db box.'; +$lang->install->errorCreateTable = 'Table create failed.'; + +$lang->install->setConfig = 'Create config file'; +$lang->install->key = 'Item'; +$lang->install->value = 'Value'; +$lang->install->saveConfig = 'Save config'; +$lang->install->save2File = '
          Try to save the config auto, but failed.
          Copy the text of the textareaand save to " %s ".'; +$lang->install->saved2File = 'The config file has saved to "%s ".'; +$lang->install->errorNotSaveConfig = "Hasn't save the config file. "; + +$lang->install->getPriv = 'Set admin'; +$lang->install->company = 'Company name'; +$lang->install->pms = 'ZenTaoPMS domain'; +$lang->install->pmsNote = 'The domain name or ip address of ZenTaoPMS, no http://'; +$lang->install->account = 'Administrator'; +$lang->install->password = 'Admin password'; +$lang->install->errorEmptyPassword = "Can't be empty"; + +$lang->install->success = "Success installed"; + +$lang->install->joinZentao = <<Please remove install.php in time。Now, you can: + +Register or login into Zetao community, feed back and get support. + +Login into ZenTaoPMS, create groups and grant priviledges. +EOT; diff --git a/module/install/lang/zh-cn.php b/module/install/lang/zh-cn.php index 77e41d863c..c89acac317 100644 --- a/module/install/lang/zh-cn.php +++ b/module/install/lang/zh-cn.php @@ -1,113 +1,113 @@ - - * @package install - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->install->common = '安装'; -$lang->install->next = '下一步'; -$lang->install->pre = '返回'; -$lang->install->reload = '刷新'; -$lang->install->error = '错误 '; - -$lang->install->start = '开始安装'; -$lang->install->keepInstalling = '继续安装当前版本'; -$lang->install->seeLatestRelease = '看看最新的版本'; -$lang->install->welcome = '欢迎使用禅道项目管理软件!'; -$lang->install->desc = <<青岛易软天创网络科技有限公司开发。 -官方网站:http://www.zentao.net -技术支持: http://www.zentao.net/ask/ -新浪微博:t.sina.com.cn/zentaopms -腾讯微博:t.qq.com/zentaopms - -您现在正在安装的版本是 %s。 -EOT; - -$lang->install->newReleased= "提示:官网网站已有最新版本%s, 发布日期于 %s。"; -$lang->install->choice = '您可以选择:'; -$lang->install->checking = '系统检查'; -$lang->install->ok = '检查通过(√)'; -$lang->install->fail = '检查失败(×)'; -$lang->install->loaded = '已加载'; -$lang->install->unloaded = '未加载'; -$lang->install->exists = '目录存在 '; -$lang->install->notExists = '目录不存在 '; -$lang->install->writable = '目录可写 '; -$lang->install->notWritable= '目录不可写 '; -$lang->install->phpINI = 'PHP配置文件'; -$lang->install->checkItem = '检查项'; -$lang->install->current = '当前配置'; -$lang->install->result = '检查结果'; -$lang->install->action = '如何修改'; - -$lang->install->phpVersion = 'PHP版本'; -$lang->install->phpFail = 'PHP版本必须大于5.2.0'; - -$lang->install->pdo = 'PDO扩展'; -$lang->install->pdoFail = '修改PHP配置文件,加载PDO扩展。'; -$lang->install->pdoMySQL = 'PDO_MySQL扩展'; -$lang->install->pdoMySQLFail = '修改PHP配置文件,加载pdo_mysql扩展。'; -$lang->install->json = 'JSON扩展'; -$lang->install->jsonFail = '修改PHP配置文件,加载JSON扩展。'; -$lang->install->tmpRoot = '临时文件目录'; -$lang->install->dataRoot = '上传文件目录'; -$lang->install->mkdir = '

          需要创建目录%s。
          linux下面命令为:
          mkdir -p %s

          '; -$lang->install->chmod = '需要修改目录 "%s" 的权限。
          linux下面命令为:
          chmod o=rwx -R %s'; - -$lang->install->settingDB = '设置数据库'; -$lang->install->webRoot = 'PMS所在网站目录'; -$lang->install->requestType = 'URL方式'; -$lang->install->defaultLang = '默认语言'; -$lang->install->dbHost = '数据库服务器'; -$lang->install->dbHostNote = '如果localhost无法访问,尝试使用127.0.0.1'; -$lang->install->dbPort = '服务器端口'; -$lang->install->dbUser = '数据库用户名'; -$lang->install->dbPassword = '数据库密码'; -$lang->install->dbName = 'PMS使用的库'; -$lang->install->dbPrefix = '建表使用的前缀'; -$lang->install->createDB = '自动创建数据库'; -$lang->install->clearDB = '清空现有数据'; - -$lang->install->requestTypes['GET'] = '普通方式'; -$lang->install->requestTypes['PATH_INFO'] = '静态友好方式'; - -$lang->install->errorConnectDB = '数据库连接失败 '; -$lang->install->errorCreateDB = '数据库创建失败'; -$lang->install->errorDBExists = '数据库已经存在,继续安装请选择清空数据'; -$lang->install->errorCreateTable = '创建表失败'; - -$lang->install->setConfig = '生成配置文件'; -$lang->install->key = '配置项'; -$lang->install->value = '值'; -$lang->install->saveConfig = '保存配置文件'; -$lang->install->save2File = '
          尝试写入配置文件,失败!
          拷贝上面文本框中的内容,将其保存到 " %s "中。您以后还可继续修改此配置文件。'; -$lang->install->saved2File = '配置信息已经成功保存到" %s "中。您后面还可继续修改此文件。'; -$lang->install->errorNotSaveConfig = '还没有保存配置文件'; - -$lang->install->getPriv = '设置帐号'; -$lang->install->company = '公司名称'; -$lang->install->pms = 'PMS地址'; -$lang->install->pmsNote = '即通过什么地址可以访问到禅道项目管理,设置域名或者IP地址即可,不需要http'; -$lang->install->account = '管理员帐号'; -$lang->install->password = '管理员密码'; -$lang->install->errorEmptyPassword = '密码不能为空'; - -$lang->install->success = "安装成功"; - -$lang->install->joinZentao = <<请及时删除install.php。现在,您可以: - -注册禅道社区,反馈建议并获得技术支持,系统赠送200积分。如果您已经拥有社区账号,只需关联账号,系统将赠送150积分。 - -直接登录禅道管理系统,设置用户及分组! -EOT; + + * @package install + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->install->common = '安装'; +$lang->install->next = '下一步'; +$lang->install->pre = '返回'; +$lang->install->reload = '刷新'; +$lang->install->error = '错误 '; + +$lang->install->start = '开始安装'; +$lang->install->keepInstalling = '继续安装当前版本'; +$lang->install->seeLatestRelease = '看看最新的版本'; +$lang->install->welcome = '欢迎使用禅道项目管理软件!'; +$lang->install->desc = <<青岛易软天创网络科技有限公司开发。 +官方网站:http://www.zentao.net +技术支持: http://www.zentao.net/ask/ +新浪微博:t.sina.com.cn/zentaopms +腾讯微博:t.qq.com/zentaopms + +您现在正在安装的版本是 %s。 +EOT; + +$lang->install->newReleased= "提示:官网网站已有最新版本%s, 发布日期于 %s。"; +$lang->install->choice = '您可以选择:'; +$lang->install->checking = '系统检查'; +$lang->install->ok = '检查通过(√)'; +$lang->install->fail = '检查失败(×)'; +$lang->install->loaded = '已加载'; +$lang->install->unloaded = '未加载'; +$lang->install->exists = '目录存在 '; +$lang->install->notExists = '目录不存在 '; +$lang->install->writable = '目录可写 '; +$lang->install->notWritable= '目录不可写 '; +$lang->install->phpINI = 'PHP配置文件'; +$lang->install->checkItem = '检查项'; +$lang->install->current = '当前配置'; +$lang->install->result = '检查结果'; +$lang->install->action = '如何修改'; + +$lang->install->phpVersion = 'PHP版本'; +$lang->install->phpFail = 'PHP版本必须大于5.2.0'; + +$lang->install->pdo = 'PDO扩展'; +$lang->install->pdoFail = '修改PHP配置文件,加载PDO扩展。'; +$lang->install->pdoMySQL = 'PDO_MySQL扩展'; +$lang->install->pdoMySQLFail = '修改PHP配置文件,加载pdo_mysql扩展。'; +$lang->install->json = 'JSON扩展'; +$lang->install->jsonFail = '修改PHP配置文件,加载JSON扩展。'; +$lang->install->tmpRoot = '临时文件目录'; +$lang->install->dataRoot = '上传文件目录'; +$lang->install->mkdir = '

          需要创建目录%s。
          linux下面命令为:
          mkdir -p %s

          '; +$lang->install->chmod = '需要修改目录 "%s" 的权限。
          linux下面命令为:
          chmod o=rwx -R %s'; + +$lang->install->settingDB = '设置数据库'; +$lang->install->webRoot = 'PMS所在网站目录'; +$lang->install->requestType = 'URL方式'; +$lang->install->defaultLang = '默认语言'; +$lang->install->dbHost = '数据库服务器'; +$lang->install->dbHostNote = '如果localhost无法访问,尝试使用127.0.0.1'; +$lang->install->dbPort = '服务器端口'; +$lang->install->dbUser = '数据库用户名'; +$lang->install->dbPassword = '数据库密码'; +$lang->install->dbName = 'PMS使用的库'; +$lang->install->dbPrefix = '建表使用的前缀'; +$lang->install->createDB = '自动创建数据库'; +$lang->install->clearDB = '清空现有数据'; + +$lang->install->requestTypes['GET'] = '普通方式'; +$lang->install->requestTypes['PATH_INFO'] = '静态友好方式'; + +$lang->install->errorConnectDB = '数据库连接失败 '; +$lang->install->errorCreateDB = '数据库创建失败'; +$lang->install->errorDBExists = '数据库已经存在,继续安装请选择清空数据'; +$lang->install->errorCreateTable = '创建表失败'; + +$lang->install->setConfig = '生成配置文件'; +$lang->install->key = '配置项'; +$lang->install->value = '值'; +$lang->install->saveConfig = '保存配置文件'; +$lang->install->save2File = '
          尝试写入配置文件,失败!
          拷贝上面文本框中的内容,将其保存到 " %s "中。您以后还可继续修改此配置文件。'; +$lang->install->saved2File = '配置信息已经成功保存到" %s "中。您后面还可继续修改此文件。'; +$lang->install->errorNotSaveConfig = '还没有保存配置文件'; + +$lang->install->getPriv = '设置帐号'; +$lang->install->company = '公司名称'; +$lang->install->pms = 'PMS地址'; +$lang->install->pmsNote = '即通过什么地址可以访问到禅道项目管理,设置域名或者IP地址即可,不需要http'; +$lang->install->account = '管理员帐号'; +$lang->install->password = '管理员密码'; +$lang->install->errorEmptyPassword = '密码不能为空'; + +$lang->install->success = "安装成功"; + +$lang->install->joinZentao = <<请及时删除install.php。现在,您可以: + +注册禅道社区,反馈建议并获得技术支持,系统赠送200积分。如果您已经拥有社区账号,只需关联账号,系统将赠送150积分。 + +直接登录禅道管理系统,设置用户及分组! +EOT; diff --git a/module/install/lang/zh-tw.php b/module/install/lang/zh-tw.php index 0be9eecb72..44956a3c06 100644 --- a/module/install/lang/zh-tw.php +++ b/module/install/lang/zh-tw.php @@ -1,113 +1,113 @@ - - * @package install - * @version $Id: zh-tw.php 2594 2012-02-20 09:06:53Z zhujinyonging@gmail.com $ - * @link http://www.zentao.net - */ -$lang->install->common = '安裝'; -$lang->install->next = '下一步'; -$lang->install->pre = '返回'; -$lang->install->reload = '刷新'; -$lang->install->error = '錯誤 '; - -$lang->install->start = '開始安裝'; -$lang->install->keepInstalling = '繼續安裝當前版本'; -$lang->install->seeLatestRelease = '看看最新的版本'; -$lang->install->welcome = '歡迎使用禪道項目管理軟件!'; -$lang->install->desc = <<青島易軟天創網絡科技有限公司開發。 -官方網站:http://www.zentao.net -技術支持: http://www.zentao.net/ask/ -新浪微博:t.sina.com.cn/zentaopms -騰訊微博:t.qq.com/zentaopms - -您現在正在安裝的版本是 %s。 -EOT; - -$lang->install->newReleased= "提示:官網網站已有最新版本%s, 發佈日期于 %s。"; -$lang->install->choice = '您可以選擇:'; -$lang->install->checking = '系統檢查'; -$lang->install->ok = '檢查通過(√)'; -$lang->install->fail = '檢查失敗(×)'; -$lang->install->loaded = '已加載'; -$lang->install->unloaded = '未加載'; -$lang->install->exists = '目錄存在 '; -$lang->install->notExists = '目錄不存在 '; -$lang->install->writable = '目錄可寫 '; -$lang->install->notWritable= '目錄不可寫 '; -$lang->install->phpINI = 'PHP配置檔案'; -$lang->install->checkItem = '檢查項'; -$lang->install->current = '當前配置'; -$lang->install->result = '檢查結果'; -$lang->install->action = '如何修改'; - -$lang->install->phpVersion = 'PHP版本'; -$lang->install->phpFail = 'PHP版本必須大於5.2.0'; - -$lang->install->pdo = 'PDO擴展'; -$lang->install->pdoFail = '修改PHP配置檔案,加載PDO擴展。'; -$lang->install->pdoMySQL = 'PDO_MySQL擴展'; -$lang->install->pdoMySQLFail = '修改PHP配置檔案,加載pdo_mysql擴展。'; -$lang->install->json = 'JSON擴展'; -$lang->install->jsonFail = '修改PHP配置檔案,加載JSON擴展。'; -$lang->install->tmpRoot = '臨時檔案目錄'; -$lang->install->dataRoot = '上傳檔案目錄'; -$lang->install->mkdir = '

          需要創建目錄%s。
          linux下面命令為:
          mkdir -p %s

          '; -$lang->install->chmod = '需要修改目錄 "%s" 的權限。
          linux下面命令為:
          chmod o=rwx -R %s'; - -$lang->install->settingDB = '設置資料庫'; -$lang->install->webRoot = 'PMS所在網站目錄'; -$lang->install->requestType = 'URL方式'; -$lang->install->defaultLang = '預設語言'; -$lang->install->dbHost = '資料庫伺服器'; -$lang->install->dbHostNote = '如果localhost無法訪問,嘗試使用127.0.0.1'; -$lang->install->dbPort = '伺服器連接埠'; -$lang->install->dbUser = '資料庫用戶名'; -$lang->install->dbPassword = '資料庫密碼'; -$lang->install->dbName = 'PMS使用的庫'; -$lang->install->dbPrefix = '建表使用的首碼'; -$lang->install->createDB = '自動創建資料庫'; -$lang->install->clearDB = '清空現有數據'; - -$lang->install->requestTypes['GET'] = '普通方式'; -$lang->install->requestTypes['PATH_INFO'] = '靜態友好方式'; - -$lang->install->errorConnectDB = '資料庫連接失敗 '; -$lang->install->errorCreateDB = '資料庫創建失敗'; -$lang->install->errorDBExists = '資料庫已經存在,繼續安裝請選擇清空數據'; -$lang->install->errorCreateTable = '創建表失敗'; - -$lang->install->setConfig = '生成配置檔案'; -$lang->install->key = '配置項'; -$lang->install->value = '值'; -$lang->install->saveConfig = '保存配置檔案'; -$lang->install->save2File = '
          嘗試寫入配置檔案,失敗!
          拷貝上面文本框中的內容,將其保存到 " %s "中。您以後還可繼續修改此配置檔案。'; -$lang->install->saved2File = '配置信息已經成功保存到" %s "中。您後面還可繼續修改此檔案。'; -$lang->install->errorNotSaveConfig = '還沒有保存配置檔案'; - -$lang->install->getPriv = '設置帳號'; -$lang->install->company = '公司名稱'; -$lang->install->pms = 'PMS地址'; -$lang->install->pmsNote = '即通過什麼地址可以訪問到禪道項目管理,設置域名或者IP地址即可,不需要http'; -$lang->install->account = '管理員帳號'; -$lang->install->password = '管理員密碼'; -$lang->install->errorEmptyPassword = '密碼不能為空'; - -$lang->install->success = "安裝成功"; - -$lang->install->joinZentao = <<請及時刪除install.php。現在,您可以: - -註冊禪道社區,反饋建議並獲得技術支持,系統贈送200積分。如果您已經擁有社區賬號,只需關聯賬號,系統將贈送150積分。 - -直接登錄禪道管理系統,設置用戶及分組! -EOT; + + * @package install + * @version $Id: zh-tw.php 2594 2012-02-20 09:06:53Z zhujinyonging@gmail.com $ + * @link http://www.zentao.net + */ +$lang->install->common = '安裝'; +$lang->install->next = '下一步'; +$lang->install->pre = '返回'; +$lang->install->reload = '刷新'; +$lang->install->error = '錯誤 '; + +$lang->install->start = '開始安裝'; +$lang->install->keepInstalling = '繼續安裝當前版本'; +$lang->install->seeLatestRelease = '看看最新的版本'; +$lang->install->welcome = '歡迎使用禪道項目管理軟件!'; +$lang->install->desc = <<青島易軟天創網絡科技有限公司開發。 +官方網站:http://www.zentao.net +技術支持: http://www.zentao.net/ask/ +新浪微博:t.sina.com.cn/zentaopms +騰訊微博:t.qq.com/zentaopms + +您現在正在安裝的版本是 %s。 +EOT; + +$lang->install->newReleased= "提示:官網網站已有最新版本%s, 發佈日期于 %s。"; +$lang->install->choice = '您可以選擇:'; +$lang->install->checking = '系統檢查'; +$lang->install->ok = '檢查通過(√)'; +$lang->install->fail = '檢查失敗(×)'; +$lang->install->loaded = '已加載'; +$lang->install->unloaded = '未加載'; +$lang->install->exists = '目錄存在 '; +$lang->install->notExists = '目錄不存在 '; +$lang->install->writable = '目錄可寫 '; +$lang->install->notWritable= '目錄不可寫 '; +$lang->install->phpINI = 'PHP配置檔案'; +$lang->install->checkItem = '檢查項'; +$lang->install->current = '當前配置'; +$lang->install->result = '檢查結果'; +$lang->install->action = '如何修改'; + +$lang->install->phpVersion = 'PHP版本'; +$lang->install->phpFail = 'PHP版本必須大於5.2.0'; + +$lang->install->pdo = 'PDO擴展'; +$lang->install->pdoFail = '修改PHP配置檔案,加載PDO擴展。'; +$lang->install->pdoMySQL = 'PDO_MySQL擴展'; +$lang->install->pdoMySQLFail = '修改PHP配置檔案,加載pdo_mysql擴展。'; +$lang->install->json = 'JSON擴展'; +$lang->install->jsonFail = '修改PHP配置檔案,加載JSON擴展。'; +$lang->install->tmpRoot = '臨時檔案目錄'; +$lang->install->dataRoot = '上傳檔案目錄'; +$lang->install->mkdir = '

          需要創建目錄%s。
          linux下面命令為:
          mkdir -p %s

          '; +$lang->install->chmod = '需要修改目錄 "%s" 的權限。
          linux下面命令為:
          chmod o=rwx -R %s'; + +$lang->install->settingDB = '設置資料庫'; +$lang->install->webRoot = 'PMS所在網站目錄'; +$lang->install->requestType = 'URL方式'; +$lang->install->defaultLang = '預設語言'; +$lang->install->dbHost = '資料庫伺服器'; +$lang->install->dbHostNote = '如果localhost無法訪問,嘗試使用127.0.0.1'; +$lang->install->dbPort = '伺服器連接埠'; +$lang->install->dbUser = '資料庫用戶名'; +$lang->install->dbPassword = '資料庫密碼'; +$lang->install->dbName = 'PMS使用的庫'; +$lang->install->dbPrefix = '建表使用的首碼'; +$lang->install->createDB = '自動創建資料庫'; +$lang->install->clearDB = '清空現有數據'; + +$lang->install->requestTypes['GET'] = '普通方式'; +$lang->install->requestTypes['PATH_INFO'] = '靜態友好方式'; + +$lang->install->errorConnectDB = '資料庫連接失敗 '; +$lang->install->errorCreateDB = '資料庫創建失敗'; +$lang->install->errorDBExists = '資料庫已經存在,繼續安裝請選擇清空數據'; +$lang->install->errorCreateTable = '創建表失敗'; + +$lang->install->setConfig = '生成配置檔案'; +$lang->install->key = '配置項'; +$lang->install->value = '值'; +$lang->install->saveConfig = '保存配置檔案'; +$lang->install->save2File = '
          嘗試寫入配置檔案,失敗!
          拷貝上面文本框中的內容,將其保存到 " %s "中。您以後還可繼續修改此配置檔案。'; +$lang->install->saved2File = '配置信息已經成功保存到" %s "中。您後面還可繼續修改此檔案。'; +$lang->install->errorNotSaveConfig = '還沒有保存配置檔案'; + +$lang->install->getPriv = '設置帳號'; +$lang->install->company = '公司名稱'; +$lang->install->pms = 'PMS地址'; +$lang->install->pmsNote = '即通過什麼地址可以訪問到禪道項目管理,設置域名或者IP地址即可,不需要http'; +$lang->install->account = '管理員帳號'; +$lang->install->password = '管理員密碼'; +$lang->install->errorEmptyPassword = '密碼不能為空'; + +$lang->install->success = "安裝成功"; + +$lang->install->joinZentao = <<請及時刪除install.php。現在,您可以: + +註冊禪道社區,反饋建議並獲得技術支持,系統贈送200積分。如果您已經擁有社區賬號,只需關聯賬號,系統將贈送150積分。 + +直接登錄禪道管理系統,設置用戶及分組! +EOT; diff --git a/module/install/model.php b/module/install/model.php index 9790934e7c..b4ce0acf04 100644 --- a/module/install/model.php +++ b/module/install/model.php @@ -1,373 +1,373 @@ - - * @package install - * @version $Id$ - * @link http://www.zentao.net - */ -?> -app->loadClass('snoopy'); - if(@$snoopy->fetchText('http://www.zentao.net/misc-getlatestrelease.json')) - { - $result = json_decode($snoopy->results); - if(isset($result->release) and $this->config->version != $result->release->version) - { - return $result->release; - } - } - return false; - } - - /** - * Check php version. - * - * @access public - * @return string ok|fail - */ - public function checkPHP() - { - return $result = version_compare(PHP_VERSION, '5.2.0') >= 0 ? 'ok' : 'fail'; - } - - /** - * Check PDO. - * - * @access public - * @return string ok|fail - */ - public function checkPDO() - { - return $result = extension_loaded('pdo') ? 'ok' : 'fail'; - } - - /** - * Check PDO::MySQL - * - * @access public - * @return string ok|fail - */ - public function checkPDOMySQL() - { - return $result = extension_loaded('pdo_mysql') ? 'ok' : 'fail'; - } - - /** - * Check json extension. - * - * @access public - * @return string ok|fail - */ - public function checkJSON() - { - return $result = extension_loaded('json') ? 'ok' : 'fail'; - } - - /** - * Get tempRoot info. - * - * @access public - * @return array - */ - public function getTmpRoot() - { - $result['path'] = $this->app->getTmpRoot(); - $result['exists'] = is_dir($result['path']); - $result['writable']= is_writable($result['path']); - return $result; - } - - /** - * Check tmpRoot. - * - * @access public - * @return string ok|fail - */ - public function checkTmpRoot() - { - $tmpRoot = $this->app->getTmpRoot(); - return $result = (is_dir($tmpRoot) and is_writable($tmpRoot)) ? 'ok' : 'fail'; - } - - /** - * Get data root - * - * @access public - * @return array - */ - public function getDataRoot() - { - $result['path'] = $this->app->getAppRoot() . 'www' . $this->app->getPathFix() . 'data'; - $result['exists'] = is_dir($result['path']); - $result['writable']= is_writable($result['path']); - return $result; - } - - /** - * Check the data root. - * - * @access public - * @return string ok|fail - */ - public function checkDataRoot() - { - $dataRoot = $this->app->getAppRoot() . 'www' . $this->app->getPathFix() . 'data'; - return $result = (is_dir($dataRoot) and is_writable($dataRoot)) ? 'ok' : 'fail'; - } - - /** - * Get the php.ini info. - * - * @access public - * @return string - */ - public function getIniInfo() - { - $iniInfo = ''; - ob_start(); - phpinfo(1); - $lines = explode("\n", strip_tags(ob_get_contents())); - ob_end_clean(); - foreach($lines as $line) if(strpos($line, 'ini') !== false) $iniInfo .= $line . "\n"; - return $iniInfo; - } - - /** - * Get web root. - * - * @access public - * @return string - */ - public function getWebRoot() - { - return rtrim(str_replace('\\', '/', pathinfo($_SERVER['PHP_SELF'], PATHINFO_DIRNAME)), '/') . '/'; - } - - /** - * Check config ok or not. - * - * @access public - * @return array - */ - public function checkConfig() - { - $return->result = 'ok'; - - /* Connect to database. */ - $this->setDBParam(); - $this->dbh = $this->connectDB(); - if(!is_object($this->dbh)) - { - $return->result = 'fail'; - $return->error = $this->lang->install->errorConnectDB . $this->dbh; - return $return; - } - - /* Get mysql version. */ - $version = $this->getMysqlVersion(); - - /* If database no exits, try create it. */ - if(!$this->dbExists()) - { - if(!$this->createDB($version)) - { - $return->result = 'fail'; - $return->error = $this->lang->install->errorCreateDB; - return $return; - } - } - elseif($this->post->clearDB == false) - { - $return->result = 'fail'; - $return->error = $this->lang->install->errorDBExists; - return $return; - } - - /* Create tables. */ - if(!$this->createTable($version)) - { - $return->result = 'fail'; - $return->error = $this->lang->install->errorCreateTable; - return $return; - } - return $return; - } - - /** - * Set database params. - * - * @access public - * @return void - */ - public function setDBParam() - { - $this->config->db->host = $this->post->dbHost; - $this->config->db->name = $this->post->dbName; - $this->config->db->user = $this->post->dbUser; - $this->config->db->password = $this->post->dbPassword; - $this->config->db->port = $this->post->dbPort; - $this->config->db->prefix = $this->post->dbPrefix; - - } - - /** - * Connect to database. - * - * @access public - * @return object - */ - public function connectDB() - { - $dsn = "mysql:host={$this->config->db->host}; port={$this->config->db->port}"; - try - { - $dbh = new PDO($dsn, $this->config->db->user, $this->config->db->password); - $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); - $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $dbh->exec("SET NAMES {$this->config->db->encoding}"); - return $dbh; - } - catch (PDOException $exception) - { - return $exception->getMessage(); - } - } - - /** - * Check db exits or not. - * - * @access public - * @return bool - */ - public function dbExists() - { - $sql = "SHOW DATABASES like '{$this->config->db->name}'"; - return $this->dbh->query($sql)->fetch(); - } - - /** - * Get mysql version. - * - * @access public - * @return string - */ - public function getMysqlVersion() - { - $sql = "SELECT VERSION() AS version"; - $result = $this->dbh->query($sql)->fetch(); - return substr($result->version, 0, 3); - } - - /** - * Create database. - * - * @param string $version - * @access public - * @return bool - */ - public function createDB($version) - { - $sql = "CREATE DATABASE `{$this->config->db->name}`"; - if($version > 4.1) $sql .= " DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"; - return $this->dbh->query($sql); - } - - /** - * Create tables. - * - * @param string $version - * @access public - * @return bool - */ - public function createTable($version) - { - $dbFile = $this->app->getAppRoot() . 'db' . $this->app->getPathFix() . 'zentao.sql'; - $tables = explode(';', file_get_contents($dbFile)); - foreach($tables as $table) - { - $table = trim($table); - if(empty($table)) continue; - - if(strpos($table, 'CREATE') !== false and $version <= 4.1) - { - $table = str_replace('DEFAULT CHARSET=utf8', '', $table); - } - elseif(strpos($table, 'DROP') !== false and $this->post->clearDB != false) - { - $table = str_replace('--', '', $table); - } - $table = str_replace('`zt_', $this->config->db->name . '.`zt_', $table); - $table = str_replace('zt_', $this->config->db->prefix, $table); - if(!$this->dbh->query($table)) return false; - } - return true; - } - - /** - * Create a comapny, set admin. - * - * @access public - * @return void - */ - public function grantPriv() - { - if($this->post->password == '') die(js::error($this->lang->install->errorEmptyPassword)); - - /* Insert a company. */ - $company->name = $this->post->company; - $company->pms = $this->post->pms; - $company->admins = ",{$this->post->account},"; - $this->dao->insert(TABLE_COMPANY)->data($company)->autoCheck()->batchCheck('name, pms', 'notempty')->check('pms', 'unique')->exec(); - - if(!dao::isError()) - { - /* Set admin. */ - $companyID = $this->dbh->lastInsertID(); - $admin->account = $this->post->account; - $admin->realname = $this->post->account; - $admin->password = md5($this->post->password); - $admin->company = $companyID; - $this->dao->insert(TABLE_USER)->data($admin)->autoCheck()->check('account', 'notempty')->exec(); - - /* Update the group and groupPriv table. */ - $this->dao->update(TABLE_GROUP)->set('company')->eq($companyID)->exec($autoCompany = false); - $this->dao->update(TABLE_GROUPPRIV)->set('company')->eq($companyID)->exec($autoCompany = false); - } - } -} + + * @package install + * @version $Id$ + * @link http://www.zentao.net + */ +?> +app->loadClass('snoopy'); + if(@$snoopy->fetchText('http://www.zentao.net/misc-getlatestrelease.json')) + { + $result = json_decode($snoopy->results); + if(isset($result->release) and $this->config->version != $result->release->version) + { + return $result->release; + } + } + return false; + } + + /** + * Check php version. + * + * @access public + * @return string ok|fail + */ + public function checkPHP() + { + return $result = version_compare(PHP_VERSION, '5.2.0') >= 0 ? 'ok' : 'fail'; + } + + /** + * Check PDO. + * + * @access public + * @return string ok|fail + */ + public function checkPDO() + { + return $result = extension_loaded('pdo') ? 'ok' : 'fail'; + } + + /** + * Check PDO::MySQL + * + * @access public + * @return string ok|fail + */ + public function checkPDOMySQL() + { + return $result = extension_loaded('pdo_mysql') ? 'ok' : 'fail'; + } + + /** + * Check json extension. + * + * @access public + * @return string ok|fail + */ + public function checkJSON() + { + return $result = extension_loaded('json') ? 'ok' : 'fail'; + } + + /** + * Get tempRoot info. + * + * @access public + * @return array + */ + public function getTmpRoot() + { + $result['path'] = $this->app->getTmpRoot(); + $result['exists'] = is_dir($result['path']); + $result['writable']= is_writable($result['path']); + return $result; + } + + /** + * Check tmpRoot. + * + * @access public + * @return string ok|fail + */ + public function checkTmpRoot() + { + $tmpRoot = $this->app->getTmpRoot(); + return $result = (is_dir($tmpRoot) and is_writable($tmpRoot)) ? 'ok' : 'fail'; + } + + /** + * Get data root + * + * @access public + * @return array + */ + public function getDataRoot() + { + $result['path'] = $this->app->getAppRoot() . 'www' . $this->app->getPathFix() . 'data'; + $result['exists'] = is_dir($result['path']); + $result['writable']= is_writable($result['path']); + return $result; + } + + /** + * Check the data root. + * + * @access public + * @return string ok|fail + */ + public function checkDataRoot() + { + $dataRoot = $this->app->getAppRoot() . 'www' . $this->app->getPathFix() . 'data'; + return $result = (is_dir($dataRoot) and is_writable($dataRoot)) ? 'ok' : 'fail'; + } + + /** + * Get the php.ini info. + * + * @access public + * @return string + */ + public function getIniInfo() + { + $iniInfo = ''; + ob_start(); + phpinfo(1); + $lines = explode("\n", strip_tags(ob_get_contents())); + ob_end_clean(); + foreach($lines as $line) if(strpos($line, 'ini') !== false) $iniInfo .= $line . "\n"; + return $iniInfo; + } + + /** + * Get web root. + * + * @access public + * @return string + */ + public function getWebRoot() + { + return rtrim(str_replace('\\', '/', pathinfo($_SERVER['PHP_SELF'], PATHINFO_DIRNAME)), '/') . '/'; + } + + /** + * Check config ok or not. + * + * @access public + * @return array + */ + public function checkConfig() + { + $return->result = 'ok'; + + /* Connect to database. */ + $this->setDBParam(); + $this->dbh = $this->connectDB(); + if(!is_object($this->dbh)) + { + $return->result = 'fail'; + $return->error = $this->lang->install->errorConnectDB . $this->dbh; + return $return; + } + + /* Get mysql version. */ + $version = $this->getMysqlVersion(); + + /* If database no exits, try create it. */ + if(!$this->dbExists()) + { + if(!$this->createDB($version)) + { + $return->result = 'fail'; + $return->error = $this->lang->install->errorCreateDB; + return $return; + } + } + elseif($this->post->clearDB == false) + { + $return->result = 'fail'; + $return->error = $this->lang->install->errorDBExists; + return $return; + } + + /* Create tables. */ + if(!$this->createTable($version)) + { + $return->result = 'fail'; + $return->error = $this->lang->install->errorCreateTable; + return $return; + } + return $return; + } + + /** + * Set database params. + * + * @access public + * @return void + */ + public function setDBParam() + { + $this->config->db->host = $this->post->dbHost; + $this->config->db->name = $this->post->dbName; + $this->config->db->user = $this->post->dbUser; + $this->config->db->password = $this->post->dbPassword; + $this->config->db->port = $this->post->dbPort; + $this->config->db->prefix = $this->post->dbPrefix; + + } + + /** + * Connect to database. + * + * @access public + * @return object + */ + public function connectDB() + { + $dsn = "mysql:host={$this->config->db->host}; port={$this->config->db->port}"; + try + { + $dbh = new PDO($dsn, $this->config->db->user, $this->config->db->password); + $dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ); + $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $dbh->exec("SET NAMES {$this->config->db->encoding}"); + return $dbh; + } + catch (PDOException $exception) + { + return $exception->getMessage(); + } + } + + /** + * Check db exits or not. + * + * @access public + * @return bool + */ + public function dbExists() + { + $sql = "SHOW DATABASES like '{$this->config->db->name}'"; + return $this->dbh->query($sql)->fetch(); + } + + /** + * Get mysql version. + * + * @access public + * @return string + */ + public function getMysqlVersion() + { + $sql = "SELECT VERSION() AS version"; + $result = $this->dbh->query($sql)->fetch(); + return substr($result->version, 0, 3); + } + + /** + * Create database. + * + * @param string $version + * @access public + * @return bool + */ + public function createDB($version) + { + $sql = "CREATE DATABASE `{$this->config->db->name}`"; + if($version > 4.1) $sql .= " DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci"; + return $this->dbh->query($sql); + } + + /** + * Create tables. + * + * @param string $version + * @access public + * @return bool + */ + public function createTable($version) + { + $dbFile = $this->app->getAppRoot() . 'db' . $this->app->getPathFix() . 'zentao.sql'; + $tables = explode(';', file_get_contents($dbFile)); + foreach($tables as $table) + { + $table = trim($table); + if(empty($table)) continue; + + if(strpos($table, 'CREATE') !== false and $version <= 4.1) + { + $table = str_replace('DEFAULT CHARSET=utf8', '', $table); + } + elseif(strpos($table, 'DROP') !== false and $this->post->clearDB != false) + { + $table = str_replace('--', '', $table); + } + $table = str_replace('`zt_', $this->config->db->name . '.`zt_', $table); + $table = str_replace('zt_', $this->config->db->prefix, $table); + if(!$this->dbh->query($table)) return false; + } + return true; + } + + /** + * Create a comapny, set admin. + * + * @access public + * @return void + */ + public function grantPriv() + { + if($this->post->password == '') die(js::error($this->lang->install->errorEmptyPassword)); + + /* Insert a company. */ + $company->name = $this->post->company; + $company->pms = $this->post->pms; + $company->admins = ",{$this->post->account},"; + $this->dao->insert(TABLE_COMPANY)->data($company)->autoCheck()->batchCheck('name, pms', 'notempty')->check('pms', 'unique')->exec(); + + if(!dao::isError()) + { + /* Set admin. */ + $companyID = $this->dbh->lastInsertID(); + $admin->account = $this->post->account; + $admin->realname = $this->post->account; + $admin->password = md5($this->post->password); + $admin->company = $companyID; + $this->dao->insert(TABLE_USER)->data($admin)->autoCheck()->check('account', 'notempty')->exec(); + + /* Update the group and groupPriv table. */ + $this->dao->update(TABLE_GROUP)->set('company')->eq($companyID)->exec($autoCompany = false); + $this->dao->update(TABLE_GROUPPRIV)->set('company')->eq($companyID)->exec($autoCompany = false); + } + } +} diff --git a/module/install/view/index.html.php b/module/install/view/index.html.php index 9578483063..49fdc2619a 100644 --- a/module/install/view/index.html.php +++ b/module/install/view/index.html.php @@ -1,33 +1,33 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - - - - - -
          install->welcome;?>
          install->desc, $config->version));?>
          - version, $config->version) > 0)):?> - install->newReleased, $latestRelease);?> -

          - install->choice; - echo html::a($latestRelease->url, $lang->install->seeLatestRelease, '_blank'); - echo html::a($this->createLink('install', 'step1'), $lang->install->keepInstalling); - ?> -

          - -

          createLink('install', 'step1'), $lang->install->start);?>

          - -
          - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + + + + + +
          install->welcome;?>
          install->desc, $config->version));?>
          + version, $config->version) > 0)):?> + install->newReleased, $latestRelease);?> +

          + install->choice; + echo html::a($latestRelease->url, $lang->install->seeLatestRelease, '_blank'); + echo html::a($this->createLink('install', 'step1'), $lang->install->keepInstalling); + ?> +

          + +

          createLink('install', 'step1'), $lang->install->start);?>

          + +
          + diff --git a/module/install/view/step1.html.php b/module/install/view/step1.html.php index ed479aa75f..df81b189a2 100644 --- a/module/install/view/step1.html.php +++ b/module/install/view/step1.html.php @@ -1,96 +1,96 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          install->checking;?>
          install->checkItem;?>install->current?>install->result?>install->action?>
          install->phpVersion;?>install->$phpResult;?>install->phpFail;?>
          install->pdo;?>install->loaded) : printf($lang->install->unloaded);?>install->$pdoResult;?>install->pdoFail;?>
          install->pdoMySQL;?>install->loaded) : printf($lang->install->unloaded);?>install->$pdoMySQLResult;?>install->pdoMySQLFail;?>
          install->json;?>install->loaded) : printf($lang->install->unloaded);?>install->$jsonResult;?>install->jsonFail;?>
          install->tmpRoot;?> - install->exists) : print($lang->install->notExists); - $tmpRootInfo['writable'] ? print($lang->install->writable) : print($lang->install->notWritable); - ?> - install->$tmpRootResult;?> - install->mkdir, $tmpRootInfo['path'], $tmpRootInfo['path']); - if(!$tmpRootInfo['writable']) printf($lang->install->chmod, $tmpRootInfo['path'], $tmpRootInfo['path']); - ?> -
          install->dataRoot;?> - install->exists) : print($lang->install->notExists); - $dataRootInfo['writable'] ? print($lang->install->writable) : print($lang->install->notWritable); - ?> - install->$dataRootResult;?> - install->mkdir, $dataRootInfo['path'], $dataRootInfo['path']); - if(!$dataRootInfo['writable']) printf($lang->install->chmod, $dataRootInfo['path'], $dataRootInfo['path']); - ?> -
          - createLink('install', 'step2'), $lang->install->next); - } - else - { - echo html::a($this->createLink('install', 'step1'), $lang->install->reload); - if($pdoResult == 'fail' or $pdoMySQLResult == 'fail') - { - echo '

          ' . '' . $lang->install->phpINI . '
          ' . nl2br($this->install->getIniInfo()) . '

          '; - } - } - ?> -
          - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          install->checking;?>
          install->checkItem;?>install->current?>install->result?>install->action?>
          install->phpVersion;?>install->$phpResult;?>install->phpFail;?>
          install->pdo;?>install->loaded) : printf($lang->install->unloaded);?>install->$pdoResult;?>install->pdoFail;?>
          install->pdoMySQL;?>install->loaded) : printf($lang->install->unloaded);?>install->$pdoMySQLResult;?>install->pdoMySQLFail;?>
          install->json;?>install->loaded) : printf($lang->install->unloaded);?>install->$jsonResult;?>install->jsonFail;?>
          install->tmpRoot;?> + install->exists) : print($lang->install->notExists); + $tmpRootInfo['writable'] ? print($lang->install->writable) : print($lang->install->notWritable); + ?> + install->$tmpRootResult;?> + install->mkdir, $tmpRootInfo['path'], $tmpRootInfo['path']); + if(!$tmpRootInfo['writable']) printf($lang->install->chmod, $tmpRootInfo['path'], $tmpRootInfo['path']); + ?> +
          install->dataRoot;?> + install->exists) : print($lang->install->notExists); + $dataRootInfo['writable'] ? print($lang->install->writable) : print($lang->install->notWritable); + ?> + install->$dataRootResult;?> + install->mkdir, $dataRootInfo['path'], $dataRootInfo['path']); + if(!$dataRootInfo['writable']) printf($lang->install->chmod, $dataRootInfo['path'], $dataRootInfo['path']); + ?> +
          + createLink('install', 'step2'), $lang->install->next); + } + else + { + echo html::a($this->createLink('install', 'step1'), $lang->install->reload); + if($pdoResult == 'fail' or $pdoMySQLResult == 'fail') + { + echo '

          ' . '' . $lang->install->phpINI . '
          ' . nl2br($this->install->getIniInfo()) . '

          '; + } + } + ?> +
          + diff --git a/module/install/view/step2.html.php b/module/install/view/step2.html.php index c59ba424e1..adc338a4f1 100644 --- a/module/install/view/step2.html.php +++ b/module/install/view/step2.html.php @@ -1,62 +1,62 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - -
          '> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          install->setConfig;?>
          install->key;?>install->value?>
          install->webRoot;?>
          install->requestType;?>install->requestTypes, 'GET', 'class=select-3');?>
          install->defaultLang;?>langs, $app->getClientLang(), 'class=select-3');?>
          install->dbHost;?>install->dbHostNote;?>
          install->dbPort;?>
          install->dbUser;?>
          install->dbPassword;?>
          install->dbName;?>
          install->dbPrefix;?>install->clearDB);?>
          -
          - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + +
          '> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          install->setConfig;?>
          install->key;?>install->value?>
          install->webRoot;?>
          install->requestType;?>install->requestTypes, 'GET', 'class=select-3');?>
          install->defaultLang;?>langs, $app->getClientLang(), 'class=select-3');?>
          install->dbHost;?>install->dbHostNote;?>
          install->dbPort;?>
          install->dbUser;?>
          install->dbPassword;?>
          install->dbName;?>
          install->dbPrefix;?>install->clearDB);?>
          +
          + diff --git a/module/install/view/step3.html.php b/module/install/view/step3.html.php index eef82046a7..dfe89b1fc7 100644 --- a/module/install/view/step3.html.php +++ b/module/install/view/step3.html.php @@ -1,72 +1,72 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - -installed = true; -\$config->debug = false; -\$config->requestType = '$requestType'; -\$config->db->host = '$dbHost'; -\$config->db->port = '$dbPort'; -\$config->db->name = '$dbName'; -\$config->db->user = '$dbUser'; -\$config->db->password = '$dbPassword'; -\$config->db->prefix = '$dbPrefix'; -\$config->webRoot = '$webRoot'; -\$config->default->domain = '$domain'; -\$config->default->lang = '$defaultLang'; -EOT; -} -?> - - - - - -
          install->error;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          - - - - - - - - - -
          install->saveConfig;?>
          - app->getConfigRoot(); - $myConfigFile = $configRoot . 'my.php'; - if(is_writable($configRoot)) - { - if(@file_put_contents($myConfigFile, $configContent)) - { - printf($lang->install->saved2File, $myConfigFile); - } - else - { - printf($lang->install->save2File, $this->app->getConfigRoot() . 'my.php'); - } - } - else - { - printf($lang->install->save2File, $this->app->getConfigRoot() . 'my.php'); - } - echo "
          "; - echo "
          " . html::a($this->createLink('install', 'step4'), $lang->install->next) . '
          '; - ?> -
          - - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + +installed = true; +\$config->debug = false; +\$config->requestType = '$requestType'; +\$config->db->host = '$dbHost'; +\$config->db->port = '$dbPort'; +\$config->db->name = '$dbName'; +\$config->db->user = '$dbUser'; +\$config->db->password = '$dbPassword'; +\$config->db->prefix = '$dbPrefix'; +\$config->webRoot = '$webRoot'; +\$config->default->domain = '$domain'; +\$config->default->lang = '$defaultLang'; +EOT; +} +?> + + + + + +
          install->error;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          + + + + + + + + + +
          install->saveConfig;?>
          + app->getConfigRoot(); + $myConfigFile = $configRoot . 'my.php'; + if(is_writable($configRoot)) + { + if(@file_put_contents($myConfigFile, $configContent)) + { + printf($lang->install->saved2File, $myConfigFile); + } + else + { + printf($lang->install->save2File, $this->app->getConfigRoot() . 'my.php'); + } + } + else + { + printf($lang->install->save2File, $this->app->getConfigRoot() . 'my.php'); + } + echo "
          "; + echo "
          " . html::a($this->createLink('install', 'step4'), $lang->install->next) . '
          '; + ?> +
          + + diff --git a/module/install/view/step4.html.php b/module/install/view/step4.html.php index ed882db51a..efb5209a94 100644 --- a/module/install/view/step4.html.php +++ b/module/install/view/step4.html.php @@ -1,52 +1,52 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - - - - - -
          install->error;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          - - - - - -
          install->success;?>
          install->afterSuccess;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          - -
          - - - - - - - - - - - - - - - - - - - - - -
          install->getPriv;?>
          install->company;?>
          install->pms;?>{$lang->install->pmsNote}";?>
          install->account;?>
          install->password;?>
          -
          - - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + + + + + +
          install->error;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          + + + + + +
          install->success;?>
          install->afterSuccess;?>
          install->pre, "onclick='javascript:history.back(-1)'");?>
          + +
          + + + + + + + + + + + + + + + + + + + + + +
          install->getPriv;?>
          install->company;?>
          install->pms;?>{$lang->install->pmsNote}";?>
          install->account;?>
          install->password;?>
          +
          + + diff --git a/module/mail/control.php b/module/mail/control.php index 679764b008..a00ab7da94 100755 --- a/module/mail/control.php +++ b/module/mail/control.php @@ -1,113 +1,113 @@ - - * @package mail - * @version $Id$ - * @link http://www.zentao.net - */ -class mail extends control -{ - /** - * Config email. - * - * @access public - * @return void - */ - public function set() - { - $this->view->mailConfig = $this->app->loadConfig('mail')->mail; - $this->display(); - } - - /** - * Save the email config. - * - * @access public - * @return void - */ - public function save() - { - if(!empty($_POST)) - { - if('gmail' == $this->post->mta) - { - $config = <<mail->turnon = {$this->post->turnon}; -\$config->mail->fromAddress = "{$this->post->fromAddress}"; -\$config->mail->mta = "gmail"; -\$config->mail->fromName = "{$this->post->fromName}"; -\$config->mail->gmail->debug = {$this->post->gmailDebug}; -\$config->mail->gmail->username = "{$this->post->gmailUsername}"; -\$config->mail->gmail->password = "{$this->post->gmailPassword}"; -EOT; - } - elseif('smtp' == $this->post->mta) - { - $position = strpos($this->post->fromAddress, '@'); - if($this->post->smtpHost == '') - { - $host = 'smtp.' . substr($this->post->fromAddress, $position + 1); - } - else - { - $host = $this->post->smtpHost; - } - - $config = <<mail->turnon = {$this->post->turnon}; -\$config->mail->fromAddress = "{$this->post->fromAddress}"; -\$config->mail->mta = "{$this->post->mta}"; -\$config->mail->fromName = "{$this->post->fromName}"; -\$config->mail->smtp->debug = {$this->post->smtpDebug}; -\$config->mail->smtp->username = "{$this->post->smtpUsername}"; -\$config->mail->smtp->password = "{$this->post->smtpPassword}"; -\$config->mail->smtp->auth = {$this->post->smtpAuth}; -\$config->mail->smtp->host = "$host"; -\$config->mail->smtp->secure = "{$this->post->smtpSecure}"; -\$config->mail->smtp->port = "{$this->post->smtpPort}"; -EOT; - } - elseif('phpmail' == $this->post->mta or 'sendmail' == $this->post->mta) - { - $config = <<mail->turnon = {$this->post->turnon}; -\$config->mail->fromAddress = "{$this->post->fromAddress}"; -\$config->mail->mta = "{$this->post->mta}"; -\$config->mail->fromName = "{$this->post->fromName}"; -EOT; - } - - /* Output config to the extconfig file of mail */ - $configPath = $this->app->getModuleExtPath('mail', 'config'); - if(is_writable($configPath)) - { - if(file_put_contents($configPath . 'zzzemail.php', $config)) - { - /* Send test mail */ - $this->mail->send($this->app->user->account, $this->lang->mail->subject, $this->lang->mail->content,"", true); - if($this->mail->isError()) echo js::error($this->mail->getError()); - echo js::confirm($this->lang->mail->confirmSave,$this->createLink('mail', 'set')); - } - else - { - $this->view->config = $config; - $this->view->configPath = $configPath; - $this->display(); - } - } - else - { - $this->view->config = $config; - $this->view->configPath = $configPath; - $this->display(); - } - } - } -} + + * @package mail + * @version $Id$ + * @link http://www.zentao.net + */ +class mail extends control +{ + /** + * Config email. + * + * @access public + * @return void + */ + public function set() + { + $this->view->mailConfig = $this->app->loadConfig('mail')->mail; + $this->display(); + } + + /** + * Save the email config. + * + * @access public + * @return void + */ + public function save() + { + if(!empty($_POST)) + { + if('gmail' == $this->post->mta) + { + $config = <<mail->turnon = {$this->post->turnon}; +\$config->mail->fromAddress = "{$this->post->fromAddress}"; +\$config->mail->mta = "gmail"; +\$config->mail->fromName = "{$this->post->fromName}"; +\$config->mail->gmail->debug = {$this->post->gmailDebug}; +\$config->mail->gmail->username = "{$this->post->gmailUsername}"; +\$config->mail->gmail->password = "{$this->post->gmailPassword}"; +EOT; + } + elseif('smtp' == $this->post->mta) + { + $position = strpos($this->post->fromAddress, '@'); + if($this->post->smtpHost == '') + { + $host = 'smtp.' . substr($this->post->fromAddress, $position + 1); + } + else + { + $host = $this->post->smtpHost; + } + + $config = <<mail->turnon = {$this->post->turnon}; +\$config->mail->fromAddress = "{$this->post->fromAddress}"; +\$config->mail->mta = "{$this->post->mta}"; +\$config->mail->fromName = "{$this->post->fromName}"; +\$config->mail->smtp->debug = {$this->post->smtpDebug}; +\$config->mail->smtp->username = "{$this->post->smtpUsername}"; +\$config->mail->smtp->password = "{$this->post->smtpPassword}"; +\$config->mail->smtp->auth = {$this->post->smtpAuth}; +\$config->mail->smtp->host = "$host"; +\$config->mail->smtp->secure = "{$this->post->smtpSecure}"; +\$config->mail->smtp->port = "{$this->post->smtpPort}"; +EOT; + } + elseif('phpmail' == $this->post->mta or 'sendmail' == $this->post->mta) + { + $config = <<mail->turnon = {$this->post->turnon}; +\$config->mail->fromAddress = "{$this->post->fromAddress}"; +\$config->mail->mta = "{$this->post->mta}"; +\$config->mail->fromName = "{$this->post->fromName}"; +EOT; + } + + /* Output config to the extconfig file of mail */ + $configPath = $this->app->getModuleExtPath('mail', 'config'); + if(is_writable($configPath)) + { + if(file_put_contents($configPath . 'zzzemail.php', $config)) + { + /* Send test mail */ + $this->mail->send($this->app->user->account, $this->lang->mail->subject, $this->lang->mail->content,"", true); + if($this->mail->isError()) echo js::error($this->mail->getError()); + echo js::confirm($this->lang->mail->confirmSave,$this->createLink('mail', 'set')); + } + else + { + $this->view->config = $config; + $this->view->configPath = $configPath; + $this->display(); + } + } + else + { + $this->view->config = $config; + $this->view->configPath = $configPath; + $this->display(); + } + } + } +} diff --git a/module/mail/model.php b/module/mail/model.php index 28f0b197b7..9b1de6aad7 100644 --- a/module/mail/model.php +++ b/module/mail/model.php @@ -1,268 +1,268 @@ - - * @package mail - * @version $Id$ - * @link http://www.zentao.net - */ -?> -app->loadClass('phpmailer', $static = true); - $this->setMTA(); - } - - /** - * Set MTA. - * - * @access public - * @return void - */ - public function setMTA() - { - if(self::$instance == null) self::$instance = new phpmailer(true); - $this->mta = self::$instance; - $this->mta->CharSet = $this->config->encoding; - $funcName = "set{$this->config->mail->mta}"; - if(!method_exists($this, $funcName)) echo $this->app->error("The MTA {$this->config->mail->mta} not supported now.", __FILE__, __LINE__, $exit = false); - $this->$funcName(); - } - - /** - * Set smtp. - * - * @access public - * @return void - */ - public function setSMTP() - { - $this->mta->isSMTP(); - $this->mta->SMTPDebug = $this->config->mail->smtp->debug; - $this->mta->Host = $this->config->mail->smtp->host; - $this->mta->SMTPAuth = $this->config->mail->smtp->auth; - $this->mta->Username = $this->config->mail->smtp->username; - $this->mta->Password = $this->config->mail->smtp->password; - if(isset($this->config->mail->smtp->port)) $this->mta->Port = $this->config->mail->smtp->port; - if(isset($this->config->mail->smtp->secure) and !empty($this->config->mail->smtp->secure))$this->mta->SMTPSecure = strtolower($this->config->mail->smtp->secure); - } - - /** - * PHPmail. - * - * @access public - * @return void - */ - public function setPhpMail() - { - $this->mta->isMail(); - } - - /** - * Sendmail. - * - * @access public - * @return void - */ - public function setSendMail() - { - $this->mta->isSendmail(); - } - - /** - * Gmail. - * - * @access public - * @return void - */ - public function setGMail() - { - $this->mta->isSMTP(); - $this->mta->SMTPDebug = $this->config->mail->gmail->debug; - $this->mta->Host = 'smtp.gmail.com'; - $this->mta->Port = 465; - $this->mta->SMTPSecure = "ssl"; - $this->mta->SMTPAuth = true; - $this->mta->Username = $this->config->mail->gmail->username; - $this->mta->Password = $this->config->mail->gmail->password; - } - - /** - * Send email - * - * @param array $toList - * @param string $subject - * @param string $body - * @param array $ccList - * @param bool $includeMe - * @access public - * @return void - */ - public function send($toList, $subject, $body = '', $ccList = '', $includeMe = false) - { - if(!$this->config->mail->turnon) return; - - /* Process toList and ccList, remove current user from them. If toList is empty, use the first cc as to. */ - if($includeMe == false) - { - $account = isset($this->app->user->account) ? $this->app->user->account : ''; - $toList = $toList ? explode(',', str_replace(' ', '', $toList)) : array(); - $ccList = $ccList ? explode(',', str_replace(' ', '', $ccList)) : array(); - - foreach($toList as $key => $to) if(trim($to) == $account or !trim($to)) unset($toList[$key]); - foreach($ccList as $key => $cc) if(trim($cc) == $account or !trim($cc)) unset($ccList[$key]); - - if(!$toList and !$ccList) return; - if(!$toList and $ccList) $toList = array(array_shift($ccList)); - $toList = join(',', $toList); - $ccList = join(',', $ccList); - } - - /* Get realname and email of users. */ - $this->loadModel('user'); - $emails = $this->user->getRealNameAndEmails(str_replace(' ', '', $toList . ',' . $ccList)); - - $this->clear(); - - try - { - $this->mta->setFrom($this->config->mail->fromAddress, $this->config->mail->fromName); - $this->setSubject($subject); - $this->setTO($toList, $emails); - $this->setCC($ccList, $emails); - $this->setBody($body); - $this->setErrorLang(); - $this->mta->send(); - } - catch (phpmailerException $e) - { - $this->errors[] = trim(strip_tags($e->errorMessage())); - } - catch (Exception $e) - { - $this->errors[] = trim(strip_tags($e->getMessage())); - } - } - - /** - * Set to address - * - * @param array $toList - * @param array $emails - * @access public - * @return void - */ - public function setTO($toList, $emails) - { - $toList = explode(',', str_replace(' ', '', $toList)); - foreach($toList as $account) - { - if(!isset($emails[$account]) or isset($emails[$account]->sended) or strpos($emails[$account]->email, '@') == false) continue; - $this->mta->addAddress($emails[$account]->email, $emails[$account]->realname); - $emails[$account]->sended = true; - } - } - - /** - * Set cc. - * - * @param array $ccList - * @param array $emails - * @access public - * @return void - */ - public function setCC($ccList, $emails) - { - $ccList = explode(',', str_replace(' ', '', $ccList)); - if(!is_array($ccList)) return; - foreach($ccList as $account) - { - if(!isset($emails[$account]) or isset($emails[$account]->sended) or strpos($emails[$account]->email, '@') == false) continue; - $this->mta->addCC($emails[$account]->email, $emails[$account]->realname); - $emails[$account]->sended = true; - } - } - - /** - * Set subject - * - * @param string $subject - * @access public - * @return void - */ - public function setSubject($subject) - { - $this->mta->Subject = stripslashes($subject); - } - - /** - * Set body. - * - * @param string $body - * @access public - * @return void - */ - public function setBody($body) - { - $this->mta->msgHtml("$body"); - } - - /** - * Set error lang. - * - * @access public - * @return void - */ - public function setErrorLang() - { - $this->mta->SetLanguage($this->app->getClientLang()); - } - - /** - * Clear. - * - * @access public - * @return void - */ - public function clear() - { - $this->mta->clearAddresses(); - $this->mta->clearAttachments(); - } - - /** - * Is error? - * - * @access public - * @return bool - */ - public function isError() - { - return !empty($this->errors); - } - - /** - * Get errors. - * - * @access public - * @return void - */ - public function getError() - { - $errors = $this->errors; - $this->errors = array(); - return $errors; - } -} + + * @package mail + * @version $Id$ + * @link http://www.zentao.net + */ +?> +app->loadClass('phpmailer', $static = true); + $this->setMTA(); + } + + /** + * Set MTA. + * + * @access public + * @return void + */ + public function setMTA() + { + if(self::$instance == null) self::$instance = new phpmailer(true); + $this->mta = self::$instance; + $this->mta->CharSet = $this->config->encoding; + $funcName = "set{$this->config->mail->mta}"; + if(!method_exists($this, $funcName)) echo $this->app->error("The MTA {$this->config->mail->mta} not supported now.", __FILE__, __LINE__, $exit = false); + $this->$funcName(); + } + + /** + * Set smtp. + * + * @access public + * @return void + */ + public function setSMTP() + { + $this->mta->isSMTP(); + $this->mta->SMTPDebug = $this->config->mail->smtp->debug; + $this->mta->Host = $this->config->mail->smtp->host; + $this->mta->SMTPAuth = $this->config->mail->smtp->auth; + $this->mta->Username = $this->config->mail->smtp->username; + $this->mta->Password = $this->config->mail->smtp->password; + if(isset($this->config->mail->smtp->port)) $this->mta->Port = $this->config->mail->smtp->port; + if(isset($this->config->mail->smtp->secure) and !empty($this->config->mail->smtp->secure))$this->mta->SMTPSecure = strtolower($this->config->mail->smtp->secure); + } + + /** + * PHPmail. + * + * @access public + * @return void + */ + public function setPhpMail() + { + $this->mta->isMail(); + } + + /** + * Sendmail. + * + * @access public + * @return void + */ + public function setSendMail() + { + $this->mta->isSendmail(); + } + + /** + * Gmail. + * + * @access public + * @return void + */ + public function setGMail() + { + $this->mta->isSMTP(); + $this->mta->SMTPDebug = $this->config->mail->gmail->debug; + $this->mta->Host = 'smtp.gmail.com'; + $this->mta->Port = 465; + $this->mta->SMTPSecure = "ssl"; + $this->mta->SMTPAuth = true; + $this->mta->Username = $this->config->mail->gmail->username; + $this->mta->Password = $this->config->mail->gmail->password; + } + + /** + * Send email + * + * @param array $toList + * @param string $subject + * @param string $body + * @param array $ccList + * @param bool $includeMe + * @access public + * @return void + */ + public function send($toList, $subject, $body = '', $ccList = '', $includeMe = false) + { + if(!$this->config->mail->turnon) return; + + /* Process toList and ccList, remove current user from them. If toList is empty, use the first cc as to. */ + if($includeMe == false) + { + $account = isset($this->app->user->account) ? $this->app->user->account : ''; + $toList = $toList ? explode(',', str_replace(' ', '', $toList)) : array(); + $ccList = $ccList ? explode(',', str_replace(' ', '', $ccList)) : array(); + + foreach($toList as $key => $to) if(trim($to) == $account or !trim($to)) unset($toList[$key]); + foreach($ccList as $key => $cc) if(trim($cc) == $account or !trim($cc)) unset($ccList[$key]); + + if(!$toList and !$ccList) return; + if(!$toList and $ccList) $toList = array(array_shift($ccList)); + $toList = join(',', $toList); + $ccList = join(',', $ccList); + } + + /* Get realname and email of users. */ + $this->loadModel('user'); + $emails = $this->user->getRealNameAndEmails(str_replace(' ', '', $toList . ',' . $ccList)); + + $this->clear(); + + try + { + $this->mta->setFrom($this->config->mail->fromAddress, $this->config->mail->fromName); + $this->setSubject($subject); + $this->setTO($toList, $emails); + $this->setCC($ccList, $emails); + $this->setBody($body); + $this->setErrorLang(); + $this->mta->send(); + } + catch (phpmailerException $e) + { + $this->errors[] = trim(strip_tags($e->errorMessage())); + } + catch (Exception $e) + { + $this->errors[] = trim(strip_tags($e->getMessage())); + } + } + + /** + * Set to address + * + * @param array $toList + * @param array $emails + * @access public + * @return void + */ + public function setTO($toList, $emails) + { + $toList = explode(',', str_replace(' ', '', $toList)); + foreach($toList as $account) + { + if(!isset($emails[$account]) or isset($emails[$account]->sended) or strpos($emails[$account]->email, '@') == false) continue; + $this->mta->addAddress($emails[$account]->email, $emails[$account]->realname); + $emails[$account]->sended = true; + } + } + + /** + * Set cc. + * + * @param array $ccList + * @param array $emails + * @access public + * @return void + */ + public function setCC($ccList, $emails) + { + $ccList = explode(',', str_replace(' ', '', $ccList)); + if(!is_array($ccList)) return; + foreach($ccList as $account) + { + if(!isset($emails[$account]) or isset($emails[$account]->sended) or strpos($emails[$account]->email, '@') == false) continue; + $this->mta->addCC($emails[$account]->email, $emails[$account]->realname); + $emails[$account]->sended = true; + } + } + + /** + * Set subject + * + * @param string $subject + * @access public + * @return void + */ + public function setSubject($subject) + { + $this->mta->Subject = stripslashes($subject); + } + + /** + * Set body. + * + * @param string $body + * @access public + * @return void + */ + public function setBody($body) + { + $this->mta->msgHtml("$body"); + } + + /** + * Set error lang. + * + * @access public + * @return void + */ + public function setErrorLang() + { + $this->mta->SetLanguage($this->app->getClientLang()); + } + + /** + * Clear. + * + * @access public + * @return void + */ + public function clear() + { + $this->mta->clearAddresses(); + $this->mta->clearAttachments(); + } + + /** + * Is error? + * + * @access public + * @return bool + */ + public function isError() + { + return !empty($this->errors); + } + + /** + * Get errors. + * + * @access public + * @return void + */ + public function getError() + { + $errors = $this->errors; + $this->errors = array(); + return $errors; + } +} diff --git a/module/mail/view/save.html.php b/module/mail/view/save.html.php index 5098fe3fc8..3cff4242ed 100755 --- a/module/mail/view/save.html.php +++ b/module/mail/view/save.html.php @@ -1,25 +1,25 @@ - - * @package mail - * @version $Id$ - * @link http://www.zentao.net - */ -include '../../common/view/header.html.php'; -?> - - - - - - - - - - -
          mail->configInfo ?>
          -
          mail->saveConfig . $configPath . 'zzzemail.php' ?>
          mail->createFile ?>
          + + * @package mail + * @version $Id$ + * @link http://www.zentao.net + */ +include '../../common/view/header.html.php'; +?> + + + + + + + + + + +
          mail->configInfo ?>
          +
          mail->saveConfig . $configPath . 'zzzemail.php' ?>
          mail->createFile ?>
          diff --git a/module/mail/view/set.html.php b/module/mail/view/set.html.php index 3484fccc2b..0305991b3a 100755 --- a/module/mail/view/set.html.php +++ b/module/mail/view/set.html.php @@ -1,110 +1,110 @@ - - * @package mail - * @version $Id$ - * @link http://www.zentao.net - */ -include '../../common/view/header.html.php'; -include '../../common/view/tablesorter.html.php';?> -turnon == 1) $turnon = 'ture'; -if(!empty($mailConfig->mta)) $mta = $mailConfig->mta; -if(!empty($mailConfig->gmail->username)) $gmailUsername = $mailConfig->gmail->username; -if(!empty($mailConfig->gmail->password)) $gmailPassword = $mailConfig->gmail->password; -if(!empty($mailConfig->smtp->username)) $smtpUsername = $mailConfig->smtp->username; -if(!empty($mailConfig->smtp->password)) $smtpPassword = $mailConfig->smtp->password; -if(!empty($mailConfig->smtp->host)) $smtpHost = $mailConfig->smtp->host; -if(!empty($mailConfig->smtp->secure)) $smtpSecure = $mailConfig->smtp->secure; -if(!empty($mailConfig->smtp->auth)) $smtpAuth = $mailConfig->smtp->auth; -if(!empty($mailConfig->smtp->port)) $smtpPort = $mailConfig->smtp->port; -?> -
          '> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          mail->setParam; ?>
          mail->turnon; ?>mail->turnonList, $turnon, 'class=select-3'); ?>
          mail->mta; ?>mail->mtaList, $mta, 'class=select-3 onchange=setMtaType(this.value)'); ?>
          mail->fromAddress; ?>fromAddress, 'class=text-3') ?>
          mail->fromName; ?>fromName, 'class=text-3') ?>
          -
          - + + * @package mail + * @version $Id$ + * @link http://www.zentao.net + */ +include '../../common/view/header.html.php'; +include '../../common/view/tablesorter.html.php';?> +turnon == 1) $turnon = 'ture'; +if(!empty($mailConfig->mta)) $mta = $mailConfig->mta; +if(!empty($mailConfig->gmail->username)) $gmailUsername = $mailConfig->gmail->username; +if(!empty($mailConfig->gmail->password)) $gmailPassword = $mailConfig->gmail->password; +if(!empty($mailConfig->smtp->username)) $smtpUsername = $mailConfig->smtp->username; +if(!empty($mailConfig->smtp->password)) $smtpPassword = $mailConfig->smtp->password; +if(!empty($mailConfig->smtp->host)) $smtpHost = $mailConfig->smtp->host; +if(!empty($mailConfig->smtp->secure)) $smtpSecure = $mailConfig->smtp->secure; +if(!empty($mailConfig->smtp->auth)) $smtpAuth = $mailConfig->smtp->auth; +if(!empty($mailConfig->smtp->port)) $smtpPort = $mailConfig->smtp->port; +?> +
          '> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          mail->setParam; ?>
          mail->turnon; ?>mail->turnonList, $turnon, 'class=select-3'); ?>
          mail->mta; ?>mail->mtaList, $mta, 'class=select-3 onchange=setMtaType(this.value)'); ?>
          mail->fromAddress; ?>fromAddress, 'class=text-3') ?>
          mail->fromName; ?>fromName, 'class=text-3') ?>
          +
          + diff --git a/module/misc/control.php b/module/misc/control.php index aa7b549189..5cbd5ac803 100644 --- a/module/misc/control.php +++ b/module/misc/control.php @@ -1,58 +1,58 @@ - - * @package misc - * @version $Id$ - * @link http://www.zentao.net - */ -class misc extends control -{ - /** - * Ping the server every 5 minutes to keep the session. - * - * @access public - * @return void - */ - public function ping() - { - if(mt_rand(0, 10) == 5) $this->loadModel('setting')->setSN(); - die(""); - } - - /** - * Show php info. - * - * @access public - * @return void - */ - public function phpinfo() - { - die(phpinfo()); - } - - /** - * Show about info of zentao. - * - * @access public - * @return void - */ - public function about() - { - die($this->display()); - } - - /** - * Update nl. - * - * @access public - * @return void - */ - public function updateNL() - { - $this->loadModel('upgrade')->updateNL(); - } -} + + * @package misc + * @version $Id$ + * @link http://www.zentao.net + */ +class misc extends control +{ + /** + * Ping the server every 5 minutes to keep the session. + * + * @access public + * @return void + */ + public function ping() + { + if(mt_rand(0, 10) == 5) $this->loadModel('setting')->setSN(); + die(""); + } + + /** + * Show php info. + * + * @access public + * @return void + */ + public function phpinfo() + { + die(phpinfo()); + } + + /** + * Show about info of zentao. + * + * @access public + * @return void + */ + public function about() + { + die($this->display()); + } + + /** + * Update nl. + * + * @access public + * @return void + */ + public function updateNL() + { + $this->loadModel('upgrade')->updateNL(); + } +} diff --git a/module/misc/lang/en.php b/module/misc/lang/en.php index f820787987..fceba8262f 100644 --- a/module/misc/lang/en.php +++ b/module/misc/lang/en.php @@ -1,58 +1,58 @@ - - * @package misc - * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $ - * @link http://www.zentao.net - */ -$lang->misc->common = 'Misc'; -$lang->misc->ping = 'Keep session'; - -$lang->misc->zentao->version = 'Version %s'; -$lang->misc->zentao->labels['about'] = 'About'; -$lang->misc->zentao->labels['support'] = 'Support'; -$lang->misc->zentao->labels['cowin'] = 'Help us'; -$lang->misc->zentao->labels['service'] = 'Services'; - -$lang->misc->zentao->about['official'] = "Official site"; -$lang->misc->zentao->about['project'] = "Project"; -$lang->misc->zentao->about['preview'] = "Demo"; -$lang->misc->zentao->about['changelog'] = "Change log"; -$lang->misc->zentao->about['license'] = "License"; -$lang->misc->zentao->about['contributors'] = "Contributors"; -$lang->misc->zentao->about['thirdparty'] = "Thirdparty"; -$lang->misc->zentao->about['sourcecode'] = "Source code"; -$lang->misc->zentao->about['extension'] = "Extensions"; - -$lang->misc->zentao->support['manual'] = "Manual"; -$lang->misc->zentao->support['faq'] = "FAQ"; -$lang->misc->zentao->support['forum'] = "Forum"; -$lang->misc->zentao->support['qqgroup'] = "QQ Grup"; -$lang->misc->zentao->support['howask'] = "How to ask"; -$lang->misc->zentao->support['vip'] = "Business"; - -$lang->misc->zentao->cowin['reportbug'] = "Report bug"; -$lang->misc->zentao->cowin['feedback'] = "Feedback feature"; -$lang->misc->zentao->cowin['devcode'] = "Commit code"; -$lang->misc->zentao->cowin['doc'] = "Write doc"; -$lang->misc->zentao->cowin['recommend'] = "Recommend"; -$lang->misc->zentao->cowin['addlink'] = "Add link"; -$lang->misc->zentao->cowin['shop'] = "Shop"; -$lang->misc->zentao->cowin['donate'] = "Donate"; -$lang->misc->zentao->cowin['cowinmore'] = "More..."; - -$lang->misc->zentao->service['install'] = 'Install service'; -$lang->misc->zentao->service['fixissue'] = 'Issue support'; -$lang->misc->zentao->service['zentaotrain']= 'ZenTao training'; -$lang->misc->zentao->service['idc'] = 'ZenTao online'; -$lang->misc->zentao->service['custom'] = 'custom develop'; -$lang->misc->zentao->service['review'] = 'ZenTao review'; -$lang->misc->zentao->service['scrumtrain'] = 'Scrum training'; -$lang->misc->zentao->service['fwtrain'] = 'ZenTaoPHP training'; -$lang->misc->zentao->service['servicemore']= 'More...'; - -$lang->misc->copyright = "Copyright ©2009-2012 Nature EasySoft Network Tecnology Co.ltd, QingDao, China"; + + * @package misc + * @version $Id: English.php 824 2010-05-02 15:32:06Z wwccss $ + * @link http://www.zentao.net + */ +$lang->misc->common = 'Misc'; +$lang->misc->ping = 'Keep session'; + +$lang->misc->zentao->version = 'Version %s'; +$lang->misc->zentao->labels['about'] = 'About'; +$lang->misc->zentao->labels['support'] = 'Support'; +$lang->misc->zentao->labels['cowin'] = 'Help us'; +$lang->misc->zentao->labels['service'] = 'Services'; + +$lang->misc->zentao->about['official'] = "Official site"; +$lang->misc->zentao->about['project'] = "Project"; +$lang->misc->zentao->about['preview'] = "Demo"; +$lang->misc->zentao->about['changelog'] = "Change log"; +$lang->misc->zentao->about['license'] = "License"; +$lang->misc->zentao->about['contributors'] = "Contributors"; +$lang->misc->zentao->about['thirdparty'] = "Thirdparty"; +$lang->misc->zentao->about['sourcecode'] = "Source code"; +$lang->misc->zentao->about['extension'] = "Extensions"; + +$lang->misc->zentao->support['manual'] = "Manual"; +$lang->misc->zentao->support['faq'] = "FAQ"; +$lang->misc->zentao->support['forum'] = "Forum"; +$lang->misc->zentao->support['qqgroup'] = "QQ Grup"; +$lang->misc->zentao->support['howask'] = "How to ask"; +$lang->misc->zentao->support['vip'] = "Business"; + +$lang->misc->zentao->cowin['reportbug'] = "Report bug"; +$lang->misc->zentao->cowin['feedback'] = "Feedback feature"; +$lang->misc->zentao->cowin['devcode'] = "Commit code"; +$lang->misc->zentao->cowin['doc'] = "Write doc"; +$lang->misc->zentao->cowin['recommend'] = "Recommend"; +$lang->misc->zentao->cowin['addlink'] = "Add link"; +$lang->misc->zentao->cowin['shop'] = "Shop"; +$lang->misc->zentao->cowin['donate'] = "Donate"; +$lang->misc->zentao->cowin['cowinmore'] = "More..."; + +$lang->misc->zentao->service['install'] = 'Install service'; +$lang->misc->zentao->service['fixissue'] = 'Issue support'; +$lang->misc->zentao->service['zentaotrain']= 'ZenTao training'; +$lang->misc->zentao->service['idc'] = 'ZenTao online'; +$lang->misc->zentao->service['custom'] = 'custom develop'; +$lang->misc->zentao->service['review'] = 'ZenTao review'; +$lang->misc->zentao->service['scrumtrain'] = 'Scrum training'; +$lang->misc->zentao->service['fwtrain'] = 'ZenTaoPHP training'; +$lang->misc->zentao->service['servicemore']= 'More...'; + +$lang->misc->copyright = "Copyright ©2009-2012 Nature EasySoft Network Tecnology Co.ltd, QingDao, China"; diff --git a/module/misc/lang/zh-cn.php b/module/misc/lang/zh-cn.php index 3f9f785e8a..b68a851323 100644 --- a/module/misc/lang/zh-cn.php +++ b/module/misc/lang/zh-cn.php @@ -1,58 +1,58 @@ - - * @package misc - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->misc->common = '杂项'; -$lang->misc->ping = '防超时'; - -$lang->misc->zentao->version = '版本%s'; -$lang->misc->zentao->labels['about'] = '关于禅道'; -$lang->misc->zentao->labels['support'] = '技术支持'; -$lang->misc->zentao->labels['cowin'] = '帮助我们'; -$lang->misc->zentao->labels['service'] = '服务列表'; - -$lang->misc->zentao->about['official'] = "官方网站"; -$lang->misc->zentao->about['project'] = "项目进展"; -$lang->misc->zentao->about['preview'] = "最新预览"; -$lang->misc->zentao->about['changelog'] = "版本历史"; -$lang->misc->zentao->about['license'] = "授权协议"; -$lang->misc->zentao->about['contributors'] = "贡献者"; -$lang->misc->zentao->about['thirdparty'] = "第三方代码"; -$lang->misc->zentao->about['sourcecode'] = "源代码"; -$lang->misc->zentao->about['extension'] = "插件平台"; - -$lang->misc->zentao->support['manual'] = "用户手册"; -$lang->misc->zentao->support['faq'] = "常见问题"; -$lang->misc->zentao->support['forum'] = "支持论坛"; -$lang->misc->zentao->support['qqgroup'] = "官方QQ群"; -$lang->misc->zentao->support['howask'] = "如何提问"; -$lang->misc->zentao->support['vip'] = "商业支持"; - -$lang->misc->zentao->cowin['reportbug'] = "汇报Bug"; -$lang->misc->zentao->cowin['feedback'] = "反馈需求"; -$lang->misc->zentao->cowin['devcode'] = "提交代码"; -$lang->misc->zentao->cowin['doc'] = "完善文档"; -$lang->misc->zentao->cowin['recommend'] = "推荐给朋友"; -$lang->misc->zentao->cowin['addlink'] = "添加友情链接"; -$lang->misc->zentao->cowin['shop'] = "逛逛我们的商店"; -$lang->misc->zentao->cowin['donate'] = "捐助我们"; -$lang->misc->zentao->cowin['cowinmore'] = "更多方式..."; - -$lang->misc->zentao->service['install'] = '禅道安装服务'; -$lang->misc->zentao->service['fixissue'] = '禅道问题解决'; -$lang->misc->zentao->service['zentaotrain']= '禅道使用培训'; -$lang->misc->zentao->service['idc'] = '禅道在线托管'; -$lang->misc->zentao->service['custom'] = '禅道定制开发'; -$lang->misc->zentao->service['review'] = '禅道点评服务'; -$lang->misc->zentao->service['scrumtrain'] = 'scrum培训'; -$lang->misc->zentao->service['fwtrain'] = '禅道PHP框架培训'; -$lang->misc->zentao->service['servicemore']= '更多服务...'; - -$lang->misc->copyright = "版权所有 ©2009-2012 青岛易软天创网络科技有限公司"; + + * @package misc + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->misc->common = '杂项'; +$lang->misc->ping = '防超时'; + +$lang->misc->zentao->version = '版本%s'; +$lang->misc->zentao->labels['about'] = '关于禅道'; +$lang->misc->zentao->labels['support'] = '技术支持'; +$lang->misc->zentao->labels['cowin'] = '帮助我们'; +$lang->misc->zentao->labels['service'] = '服务列表'; + +$lang->misc->zentao->about['official'] = "官方网站"; +$lang->misc->zentao->about['project'] = "项目进展"; +$lang->misc->zentao->about['preview'] = "最新预览"; +$lang->misc->zentao->about['changelog'] = "版本历史"; +$lang->misc->zentao->about['license'] = "授权协议"; +$lang->misc->zentao->about['contributors'] = "贡献者"; +$lang->misc->zentao->about['thirdparty'] = "第三方代码"; +$lang->misc->zentao->about['sourcecode'] = "源代码"; +$lang->misc->zentao->about['extension'] = "插件平台"; + +$lang->misc->zentao->support['manual'] = "用户手册"; +$lang->misc->zentao->support['faq'] = "常见问题"; +$lang->misc->zentao->support['forum'] = "支持论坛"; +$lang->misc->zentao->support['qqgroup'] = "官方QQ群"; +$lang->misc->zentao->support['howask'] = "如何提问"; +$lang->misc->zentao->support['vip'] = "商业支持"; + +$lang->misc->zentao->cowin['reportbug'] = "汇报Bug"; +$lang->misc->zentao->cowin['feedback'] = "反馈需求"; +$lang->misc->zentao->cowin['devcode'] = "提交代码"; +$lang->misc->zentao->cowin['doc'] = "完善文档"; +$lang->misc->zentao->cowin['recommend'] = "推荐给朋友"; +$lang->misc->zentao->cowin['addlink'] = "添加友情链接"; +$lang->misc->zentao->cowin['shop'] = "逛逛我们的商店"; +$lang->misc->zentao->cowin['donate'] = "捐助我们"; +$lang->misc->zentao->cowin['cowinmore'] = "更多方式..."; + +$lang->misc->zentao->service['install'] = '禅道安装服务'; +$lang->misc->zentao->service['fixissue'] = '禅道问题解决'; +$lang->misc->zentao->service['zentaotrain']= '禅道使用培训'; +$lang->misc->zentao->service['idc'] = '禅道在线托管'; +$lang->misc->zentao->service['custom'] = '禅道定制开发'; +$lang->misc->zentao->service['review'] = '禅道点评服务'; +$lang->misc->zentao->service['scrumtrain'] = 'scrum培训'; +$lang->misc->zentao->service['fwtrain'] = '禅道PHP框架培训'; +$lang->misc->zentao->service['servicemore']= '更多服务...'; + +$lang->misc->copyright = "版权所有 ©2009-2012 青岛易软天创网络科技有限公司"; diff --git a/module/misc/lang/zh-tw.php b/module/misc/lang/zh-tw.php index 82711f436d..5867c2c1de 100644 --- a/module/misc/lang/zh-tw.php +++ b/module/misc/lang/zh-tw.php @@ -1,58 +1,58 @@ - - * @package misc - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->misc->common = '雜項'; -$lang->misc->ping = '防超時'; - -$lang->misc->zentao->version = '版本%s'; -$lang->misc->zentao->labels['about'] = '關於禪道'; -$lang->misc->zentao->labels['support'] = '技術支持'; -$lang->misc->zentao->labels['cowin'] = '幫助我們'; -$lang->misc->zentao->labels['service'] = '服務列表'; - -$lang->misc->zentao->about['official'] = "官方網站"; -$lang->misc->zentao->about['project'] = "項目進展"; -$lang->misc->zentao->about['preview'] = "最新預覽"; -$lang->misc->zentao->about['changelog'] = "版本歷史"; -$lang->misc->zentao->about['license'] = "授權協議"; -$lang->misc->zentao->about['contributors'] = "貢獻者"; -$lang->misc->zentao->about['thirdparty'] = "第三方代碼"; -$lang->misc->zentao->about['sourcecode'] = "原始碼"; -$lang->misc->zentao->about['extension'] = "插件平台"; - -$lang->misc->zentao->support['manual'] = "用戶手冊"; -$lang->misc->zentao->support['faq'] = "常見問題"; -$lang->misc->zentao->support['forum'] = "支持論壇"; -$lang->misc->zentao->support['qqgroup'] = "官方QQ群"; -$lang->misc->zentao->support['howask'] = "如何提問"; -$lang->misc->zentao->support['vip'] = "商業支持"; - -$lang->misc->zentao->cowin['reportbug'] = "彙報Bug"; -$lang->misc->zentao->cowin['feedback'] = "反饋需求"; -$lang->misc->zentao->cowin['devcode'] = "提交代碼"; -$lang->misc->zentao->cowin['doc'] = "完善文檔"; -$lang->misc->zentao->cowin['recommend'] = "推薦給朋友"; -$lang->misc->zentao->cowin['addlink'] = "添加友情連結"; -$lang->misc->zentao->cowin['shop'] = "逛逛我們的商店"; -$lang->misc->zentao->cowin['donate'] = "捐助我們"; -$lang->misc->zentao->cowin['cowinmore'] = "更多方式..."; - -$lang->misc->zentao->service['install'] = '禪道安裝服務'; -$lang->misc->zentao->service['fixissue'] = '禪道問題解決'; -$lang->misc->zentao->service['zentaotrain']= '禪道使用培訓'; -$lang->misc->zentao->service['idc'] = '禪道在綫託管'; -$lang->misc->zentao->service['custom'] = '禪道定製開發'; -$lang->misc->zentao->service['review'] = '禪道點評服務'; -$lang->misc->zentao->service['scrumtrain'] = 'scrum培訓'; -$lang->misc->zentao->service['fwtrain'] = '禪道PHP框架培訓'; -$lang->misc->zentao->service['servicemore']= '更多服務...'; - -$lang->misc->copyright = "版權所有 ©2009-2012 青島易軟天創網絡科技有限公司"; + + * @package misc + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->misc->common = '雜項'; +$lang->misc->ping = '防超時'; + +$lang->misc->zentao->version = '版本%s'; +$lang->misc->zentao->labels['about'] = '關於禪道'; +$lang->misc->zentao->labels['support'] = '技術支持'; +$lang->misc->zentao->labels['cowin'] = '幫助我們'; +$lang->misc->zentao->labels['service'] = '服務列表'; + +$lang->misc->zentao->about['official'] = "官方網站"; +$lang->misc->zentao->about['project'] = "項目進展"; +$lang->misc->zentao->about['preview'] = "最新預覽"; +$lang->misc->zentao->about['changelog'] = "版本歷史"; +$lang->misc->zentao->about['license'] = "授權協議"; +$lang->misc->zentao->about['contributors'] = "貢獻者"; +$lang->misc->zentao->about['thirdparty'] = "第三方代碼"; +$lang->misc->zentao->about['sourcecode'] = "原始碼"; +$lang->misc->zentao->about['extension'] = "插件平台"; + +$lang->misc->zentao->support['manual'] = "用戶手冊"; +$lang->misc->zentao->support['faq'] = "常見問題"; +$lang->misc->zentao->support['forum'] = "支持論壇"; +$lang->misc->zentao->support['qqgroup'] = "官方QQ群"; +$lang->misc->zentao->support['howask'] = "如何提問"; +$lang->misc->zentao->support['vip'] = "商業支持"; + +$lang->misc->zentao->cowin['reportbug'] = "彙報Bug"; +$lang->misc->zentao->cowin['feedback'] = "反饋需求"; +$lang->misc->zentao->cowin['devcode'] = "提交代碼"; +$lang->misc->zentao->cowin['doc'] = "完善文檔"; +$lang->misc->zentao->cowin['recommend'] = "推薦給朋友"; +$lang->misc->zentao->cowin['addlink'] = "添加友情連結"; +$lang->misc->zentao->cowin['shop'] = "逛逛我們的商店"; +$lang->misc->zentao->cowin['donate'] = "捐助我們"; +$lang->misc->zentao->cowin['cowinmore'] = "更多方式..."; + +$lang->misc->zentao->service['install'] = '禪道安裝服務'; +$lang->misc->zentao->service['fixissue'] = '禪道問題解決'; +$lang->misc->zentao->service['zentaotrain']= '禪道使用培訓'; +$lang->misc->zentao->service['idc'] = '禪道在綫託管'; +$lang->misc->zentao->service['custom'] = '禪道定製開發'; +$lang->misc->zentao->service['review'] = '禪道點評服務'; +$lang->misc->zentao->service['scrumtrain'] = 'scrum培訓'; +$lang->misc->zentao->service['fwtrain'] = '禪道PHP框架培訓'; +$lang->misc->zentao->service['servicemore']= '更多服務...'; + +$lang->misc->copyright = "版權所有 ©2009-2012 青島易軟天創網絡科技有限公司"; diff --git a/module/misc/model.php b/module/misc/model.php index 032fc8e819..5989c648aa 100644 --- a/module/misc/model.php +++ b/module/misc/model.php @@ -1,16 +1,16 @@ - - * @package misc - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + * @package misc + * @version $Id$ + * @link http://www.zentao.net + */ +?> + - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -class my extends control -{ - /** - * Construct function. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('user'); - $this->loadModel('dept'); - $this->my->setMenu(); - } - - /** - * Index page, goto todo. - * - * @access public - * @return void - */ - public function index() - { - $account = $this->app->user->account; - - /* Get project and product stats. */ - $projectStats = $this->loadModel('project')->getProjectStats(); - $productStats = $this->loadModel('product')->getStats(); - - /* Set the dynamic pager. */ - $this->app->loadClass('pager', true); - $pager = new pager(0, $this->config->my->dynamicCounts); - - $this->view->projectStats = $projectStats; - $this->view->productStats = $productStats; - $this->view->actions = $this->loadModel('action')->getDynamic('all', 'all', 'date_desc', $pager); - $this->view->todos = $this->loadModel('todo')->getList('all', $account, 'wait, doing', $this->config->my->todoCounts); - $this->view->tasks = $this->loadModel('task')->getUserTasks($account, 'assignedTo', $this->config->my->taskCounts); - $this->view->bugs = $this->loadModel('bug')->getUserBugPairs($account, false, $this->config->my->bugCounts); - $this->view->users = $this->loadModel('user')->getPairs('noletter|withguest'); - $this->view->header->title = $this->lang->my->common; - - $this->display(); - } - - /** - * My todos. - * - * @param string $type - * @param string $account - * @param string $status - * @access public - * @return void - */ - public function todo($type = 'today', $account = '', $status = 'all') - { - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('todoList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('taskList', $uri); - - /* The header and position. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->todo; - $this->view->position[] = $this->lang->my->todo; - - /* Assign. */ - $this->view->dates = $this->loadModel('todo')->buildDateList(); - $this->view->todos = $this->todo->getList($type, $account, $status); - $this->view->date = (int)$type == 0 ? $this->todo->today() : $type; - $this->view->type = $type; - $this->view->account = $this->app->user->account; - $this->view->importFuture = ($type == 'before' or $type == TODOMODEL::DAY_IN_FUTURE); - - $this->display(); - } - - /** - * My stories. - * - * @access public - * @return void - */ - public function story($type = 'assignedto') - { - /* Save session. */ - $this->session->set('storyList', $this->app->getURI(true)); - - /* Assign. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->story; - $this->view->position[] = $this->lang->my->story; - $this->view->stories = $this->loadModel('story')->getUserStories($this->app->user->account, $type); - $this->view->users = $this->user->getPairs('noletter'); - $this->view->type = $type; - - $this->display(); - } - - /** - * My tasks. - * - * @param string $type the browse type - * @access public - * @return void - */ - public function task($type = 'assignedto') - { - /* Save session. */ - $this->session->set('taskList', $this->app->getURI(true)); - $this->session->set('storyList', $this->app->getURI(true)); - - /* Assign. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->task; - $this->view->position[] = $this->lang->my->task; - $this->view->tabID = 'task'; - $this->view->tasks = $this->loadModel('task')->getUserTasks($this->app->user->account, $type); - $this->view->type = $type; - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * My bugs. - * - * @param string $type - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function bug($type = 'assigntome', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. load Lang. */ - $this->session->set('bugList', $this->app->getURI(true)); - $this->app->loadLang('bug'); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - $bugs = array(); - if($type == 'assigntome') - { - $bugs = $this->dao->select('t1.*') - ->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) - ->andWhere('t1.assignedTo')->eq($this->app->user->account) - ->orderBy('t1.id_desc')->page($pager)->fetchAll(); - } - elseif($type == 'openedbyme') - { - $bugs = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - elseif($type == 'resolvedbyme') - { - $bugs = $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - elseif($type == 'closedbyme') - { - $bugs = $this->dao->findByClosedBy($this->app->user->account)->from(TABLE_BUG) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /* assign. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->bug; - $this->view->position[] = $this->lang->my->bug; - $this->view->bugs = $bugs; - $this->view->users = $this->user->getPairs('noletter'); - $this->view->tabID = 'bug'; - $this->view->type = $type; - $this->view->pager = $pager; - - $this->display(); - } - - /** - * My test task. - * - * @access public - * @return void - */ - public function testtask() - { - /* Save session. */ - $this->session->set('testtaskList', $this->app->getURI(true)); - - $this->app->loadLang('testcase'); - - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->testTask; - $this->view->position[] = $this->lang->my->testTask; - $this->view->tasks = $this->loadModel('testtask')->getByUser($this->app->user->account); - - $this->display(); - - } - - /** - * My test case. - * - * @param string $type - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function testcase($type = 'assigntome', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session, load lang. */ - $this->session->set('caseList', $this->app->getURI(true)); - $this->app->loadLang('testcase'); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - $cases = array(); - if($type == 'assigntome') - { - $cases = $this->dao->select('t1.assignedTo AS assignedTo, t2.*')->from(TABLE_TESTRUN)->alias('t1') - ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') - ->leftJoin(TABLE_TESTTASK)->alias('t3')->on('t1.task = t3.id') - ->Where('t1.assignedTo')->eq($this->app->user->account) - ->andWhere('t1.status')->ne('done') - ->andWhere('t3.status')->ne('done') - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - elseif($type == 'donebyme') - { - $cases = $this->dao->select('t1.assignedTo AS assignedTo, t2.*')->from(TABLE_TESTRUN)->alias('t1') - ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') - ->Where('t1.assignedTo')->eq($this->app->user->account) - ->andWhere('t1.status')->eq('done') - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - elseif($type == 'openedbyme') - { - $cases = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_CASE) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /* Assign. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->testCase; - $this->view->position[] = $this->lang->my->testCase; - $this->view->cases = $cases; - $this->view->users = $this->user->getPairs('noletter'); - $this->view->tabID = 'test'; - $this->view->type = $type; - $this->view->pager = $pager; - - $this->display(); - } - - /** - * My projects. - * - * @access public - * @return void - */ - public function project() - { - $this->app->loadLang('project'); - - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->myProject; - $this->view->position[] = $this->lang->my->myProject; - $this->view->tabID = 'project'; - $this->view->projects = @array_reverse($this->user->getProjects($this->app->user->account)); - - $this->display(); - } - - /** - * Edit profile - * - * @access public - * @return void - */ - public function editProfile() - { - if($this->app->user->account == 'guest') die(js::alert('guest') . js::locate('back')); - if(!empty($_POST)) - { - $this->user->update($this->app->user->id); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('my', 'profile'), 'parent')); - } - - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->editProfile; - $this->view->position[] = $this->lang->my->editProfile; - $this->view->user = $this->user->getById($this->app->user->id); - - $this->display(); - } - - /** - * View my profile. - * - * @access public - * @return void - */ - public function profile() - { - if($this->app->user->account == 'guest') die(js::alert('guest') . js::locate('back')); - $user = $this->user->getById($this->app->user->account); - $deptPath = $this->dept->getParents($user->dept); - $this->view->deptPath = $deptPath; - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->profile; - $this->view->position[] = $this->lang->my->profile; - $this->view->user = $this->user->getById($this->app->user->id); - $this->display(); - } - - /** - * My dynamic. - * - * @param string $type - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function dynamic($type = 'today', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - /* Set the pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - - /* The header and position. */ - $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->dynamic; - $this->view->position[] = $this->lang->my->dynamic; - - /* Assign. */ - $this->view->type = $type; - $this->view->actions = $this->loadModel('action')->getDynamic($this->app->user->account, $type, $orderBy, $pager); - $this->display(); - } - -} + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +class my extends control +{ + /** + * Construct function. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('user'); + $this->loadModel('dept'); + $this->my->setMenu(); + } + + /** + * Index page, goto todo. + * + * @access public + * @return void + */ + public function index() + { + $account = $this->app->user->account; + + /* Get project and product stats. */ + $projectStats = $this->loadModel('project')->getProjectStats(); + $productStats = $this->loadModel('product')->getStats(); + + /* Set the dynamic pager. */ + $this->app->loadClass('pager', true); + $pager = new pager(0, $this->config->my->dynamicCounts); + + $this->view->projectStats = $projectStats; + $this->view->productStats = $productStats; + $this->view->actions = $this->loadModel('action')->getDynamic('all', 'all', 'date_desc', $pager); + $this->view->todos = $this->loadModel('todo')->getList('all', $account, 'wait, doing', $this->config->my->todoCounts); + $this->view->tasks = $this->loadModel('task')->getUserTasks($account, 'assignedTo', $this->config->my->taskCounts); + $this->view->bugs = $this->loadModel('bug')->getUserBugPairs($account, false, $this->config->my->bugCounts); + $this->view->users = $this->loadModel('user')->getPairs('noletter|withguest'); + $this->view->header->title = $this->lang->my->common; + + $this->display(); + } + + /** + * My todos. + * + * @param string $type + * @param string $account + * @param string $status + * @access public + * @return void + */ + public function todo($type = 'today', $account = '', $status = 'all') + { + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('todoList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('taskList', $uri); + + /* The header and position. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->todo; + $this->view->position[] = $this->lang->my->todo; + + /* Assign. */ + $this->view->dates = $this->loadModel('todo')->buildDateList(); + $this->view->todos = $this->todo->getList($type, $account, $status); + $this->view->date = (int)$type == 0 ? $this->todo->today() : $type; + $this->view->type = $type; + $this->view->account = $this->app->user->account; + $this->view->importFuture = ($type == 'before' or $type == TODOMODEL::DAY_IN_FUTURE); + + $this->display(); + } + + /** + * My stories. + * + * @access public + * @return void + */ + public function story($type = 'assignedto') + { + /* Save session. */ + $this->session->set('storyList', $this->app->getURI(true)); + + /* Assign. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->story; + $this->view->position[] = $this->lang->my->story; + $this->view->stories = $this->loadModel('story')->getUserStories($this->app->user->account, $type); + $this->view->users = $this->user->getPairs('noletter'); + $this->view->type = $type; + + $this->display(); + } + + /** + * My tasks. + * + * @param string $type the browse type + * @access public + * @return void + */ + public function task($type = 'assignedto') + { + /* Save session. */ + $this->session->set('taskList', $this->app->getURI(true)); + $this->session->set('storyList', $this->app->getURI(true)); + + /* Assign. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->task; + $this->view->position[] = $this->lang->my->task; + $this->view->tabID = 'task'; + $this->view->tasks = $this->loadModel('task')->getUserTasks($this->app->user->account, $type); + $this->view->type = $type; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * My bugs. + * + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function bug($type = 'assigntome', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. load Lang. */ + $this->session->set('bugList', $this->app->getURI(true)); + $this->app->loadLang('bug'); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $bugs = array(); + if($type == 'assigntome') + { + $bugs = $this->dao->select('t1.*') + ->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) + ->andWhere('t1.assignedTo')->eq($this->app->user->account) + ->orderBy('t1.id_desc')->page($pager)->fetchAll(); + } + elseif($type == 'openedbyme') + { + $bugs = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_BUG) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($type == 'resolvedbyme') + { + $bugs = $this->dao->findByResolvedBy($this->app->user->account)->from(TABLE_BUG) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($type == 'closedbyme') + { + $bugs = $this->dao->findByClosedBy($this->app->user->account)->from(TABLE_BUG) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* assign. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->bug; + $this->view->position[] = $this->lang->my->bug; + $this->view->bugs = $bugs; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->tabID = 'bug'; + $this->view->type = $type; + $this->view->pager = $pager; + + $this->display(); + } + + /** + * My test task. + * + * @access public + * @return void + */ + public function testtask() + { + /* Save session. */ + $this->session->set('testtaskList', $this->app->getURI(true)); + + $this->app->loadLang('testcase'); + + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->testTask; + $this->view->position[] = $this->lang->my->testTask; + $this->view->tasks = $this->loadModel('testtask')->getByUser($this->app->user->account); + + $this->display(); + + } + + /** + * My test case. + * + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function testcase($type = 'assigntome', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session, load lang. */ + $this->session->set('caseList', $this->app->getURI(true)); + $this->app->loadLang('testcase'); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $cases = array(); + if($type == 'assigntome') + { + $cases = $this->dao->select('t1.assignedTo AS assignedTo, t2.*')->from(TABLE_TESTRUN)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') + ->leftJoin(TABLE_TESTTASK)->alias('t3')->on('t1.task = t3.id') + ->Where('t1.assignedTo')->eq($this->app->user->account) + ->andWhere('t1.status')->ne('done') + ->andWhere('t3.status')->ne('done') + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($type == 'donebyme') + { + $cases = $this->dao->select('t1.assignedTo AS assignedTo, t2.*')->from(TABLE_TESTRUN)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') + ->Where('t1.assignedTo')->eq($this->app->user->account) + ->andWhere('t1.status')->eq('done') + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + elseif($type == 'openedbyme') + { + $cases = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_CASE) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* Assign. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->testCase; + $this->view->position[] = $this->lang->my->testCase; + $this->view->cases = $cases; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->tabID = 'test'; + $this->view->type = $type; + $this->view->pager = $pager; + + $this->display(); + } + + /** + * My projects. + * + * @access public + * @return void + */ + public function project() + { + $this->app->loadLang('project'); + + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->myProject; + $this->view->position[] = $this->lang->my->myProject; + $this->view->tabID = 'project'; + $this->view->projects = @array_reverse($this->user->getProjects($this->app->user->account)); + + $this->display(); + } + + /** + * Edit profile + * + * @access public + * @return void + */ + public function editProfile() + { + if($this->app->user->account == 'guest') die(js::alert('guest') . js::locate('back')); + if(!empty($_POST)) + { + $this->user->update($this->app->user->id); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('my', 'profile'), 'parent')); + } + + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->editProfile; + $this->view->position[] = $this->lang->my->editProfile; + $this->view->user = $this->user->getById($this->app->user->id); + + $this->display(); + } + + /** + * View my profile. + * + * @access public + * @return void + */ + public function profile() + { + if($this->app->user->account == 'guest') die(js::alert('guest') . js::locate('back')); + $user = $this->user->getById($this->app->user->account); + $deptPath = $this->dept->getParents($user->dept); + $this->view->deptPath = $deptPath; + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->profile; + $this->view->position[] = $this->lang->my->profile; + $this->view->user = $this->user->getById($this->app->user->id); + $this->display(); + } + + /** + * My dynamic. + * + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dynamic($type = 'today', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + /* Set the pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + + /* The header and position. */ + $this->view->header->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->dynamic; + $this->view->position[] = $this->lang->my->dynamic; + + /* Assign. */ + $this->view->type = $type; + $this->view->actions = $this->loadModel('action')->getDynamic($this->app->user->account, $type, $orderBy, $pager); + $this->display(); + } + +} diff --git a/module/my/model.php b/module/my/model.php index 6ec4ed6c3d..dedad78817 100644 --- a/module/my/model.php +++ b/module/my/model.php @@ -1,26 +1,26 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> -lang->my->menu->account = sprintf($this->lang->my->menu->account, $this->app->user->realname); - } -} + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> +lang->my->menu->account = sprintf($this->lang->my->menu->account, $this->app->user->realname); + } +} diff --git a/module/my/view/bug.html.php b/module/my/view/bug.html.php index 6d5d2be71d..8b9d551949 100644 --- a/module/my/view/bug.html.php +++ b/module/my/view/bug.html.php @@ -1,65 +1,65 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          -
          - " . html::a(inlink('bug', "type=assigntome"), $lang->bug->assignToMe) . ""; - echo "" . html::a(inlink('bug', "type=openedbyme"), $lang->bug->openedByMe) . ""; - echo "" . html::a(inlink('bug', "type=resolvedbyme"), $lang->bug->resolvedByMe) . ""; - echo "" . html::a(inlink('bug', "type=closedbyme"), $lang->bug->closedByMe) . ""; - ?> -
          -
          -recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>bug->severityAB;?>priAB;?>typeAB;?>bug->title;?>openedByAB;?>bug->resolvedByAB;?>bug->resolutionAB;?>actions;?>
          createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>bug->typeList[$bug->type]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?> - id"; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - ?> -
          show();?>
          - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          +
          + " . html::a(inlink('bug', "type=assigntome"), $lang->bug->assignToMe) . ""; + echo "" . html::a(inlink('bug', "type=openedbyme"), $lang->bug->openedByMe) . ""; + echo "" . html::a(inlink('bug', "type=resolvedbyme"), $lang->bug->resolvedByMe) . ""; + echo "" . html::a(inlink('bug', "type=closedbyme"), $lang->bug->closedByMe) . ""; + ?> +
          +
          +recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>bug->severityAB;?>priAB;?>typeAB;?>bug->title;?>openedByAB;?>bug->resolvedByAB;?>bug->resolutionAB;?>actions;?>
          createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>bug->typeList[$bug->type]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?> + id"; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + ?> +
          show();?>
          + + diff --git a/module/my/view/dynamic.html.php b/module/my/view/dynamic.html.php index a3423594fe..3f890595e2 100644 --- a/module/my/view/dynamic.html.php +++ b/module/my/view/dynamic.html.php @@ -1,55 +1,55 @@ -dynamic view file of dashboard module of ZenTaoPMS. - * - * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) - * @license LGPL (http://www.gnu.org/licenses/lgpl.html) - * @author Chunsheng Wang - * @package dashboard - * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ - * @link http://www.zentao.net - */ -?> - - -
          - ' . html::a(inlink('dynamic', "type=today"), $lang->action->dynamic->today) . ''; - echo '' . html::a(inlink('dynamic', "type=yesterday"), $lang->action->dynamic->yesterday) . ''; - echo '' . html::a(inlink('dynamic', "type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; - echo '' . html::a(inlink('dynamic', "type=thisweek"), $lang->action->dynamic->thisWeek) . ''; - echo '' . html::a(inlink('dynamic', "type=lastweek"), $lang->action->dynamic->lastWeek) . ''; - echo '' . html::a(inlink('dynamic', "type=thismonth"), $lang->action->dynamic->thisMonth) . ''; - echo '' . html::a(inlink('dynamic', "type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; - echo '' . html::a(inlink('dynamic', "type=all"), $lang->action->dynamic->all) . ''; - ?> -
          - - - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - -
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>user->realname;?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          - - +dynamic view file of dashboard module of ZenTaoPMS. + * + * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) + * @license LGPL (http://www.gnu.org/licenses/lgpl.html) + * @author Chunsheng Wang + * @package dashboard + * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ + * @link http://www.zentao.net + */ +?> + + +
          + ' . html::a(inlink('dynamic', "type=today"), $lang->action->dynamic->today) . ''; + echo '' . html::a(inlink('dynamic', "type=yesterday"), $lang->action->dynamic->yesterday) . ''; + echo '' . html::a(inlink('dynamic', "type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; + echo '' . html::a(inlink('dynamic', "type=thisweek"), $lang->action->dynamic->thisWeek) . ''; + echo '' . html::a(inlink('dynamic', "type=lastweek"), $lang->action->dynamic->lastWeek) . ''; + echo '' . html::a(inlink('dynamic', "type=thismonth"), $lang->action->dynamic->thisMonth) . ''; + echo '' . html::a(inlink('dynamic', "type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; + echo '' . html::a(inlink('dynamic', "type=all"), $lang->action->dynamic->all) . ''; + ?> +
          + + + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + +
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>user->realname;?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          + + diff --git a/module/my/view/editprofile.html.php b/module/my/view/editprofile.html.php index e8aecb398d..3a2d024ea2 100644 --- a/module/my/view/editprofile.html.php +++ b/module/my/view/editprofile.html.php @@ -1,100 +1,100 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          my->editProfile;?>
          user->account;?>account . html::hidden('account',$user->account);?>
          user->realname;?>realname);?>
          user->commiter;?>commiter);?>
          user->email;?>email);?>
          user->gender;?>user->genderList, $user->gender);?>
          user->password;?>
          user->password2;?>
          user->birthyear;?>birthday,"class='date'");?>
          user->join;?>account, "readonly"); - echo $user->join; - echo html::hidden('join',$user->join); - ?> -
          user->msn;?>msn);?>
          user->qq;?>qq);?>
          user->yahoo;?>yahoo);?>
          user->gtalk;?>gtalk);?>
          user->wangwang;?>wangwang);?>
          user->mobile;?>mobile);?>
          user->phone;?>phone);?>
          user->address;?>address);?>
          user->zipcode;?>zipcode);?>
          -
          - + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          my->editProfile;?>
          user->account;?>account . html::hidden('account',$user->account);?>
          user->realname;?>realname);?>
          user->commiter;?>commiter);?>
          user->email;?>email);?>
          user->gender;?>user->genderList, $user->gender);?>
          user->password;?>
          user->password2;?>
          user->birthyear;?>birthday,"class='date'");?>
          user->join;?>account, "readonly"); + echo $user->join; + echo html::hidden('join',$user->join); + ?> +
          user->msn;?>msn);?>
          user->qq;?>qq);?>
          user->yahoo;?>yahoo);?>
          user->gtalk;?>gtalk);?>
          user->wangwang;?>wangwang);?>
          user->mobile;?>mobile);?>
          user->phone;?>phone);?>
          user->address;?>address);?>
          user->zipcode;?>zipcode);?>
          +
          + diff --git a/module/my/view/index.html.php b/module/my/view/index.html.php index 69641ea887..5d90aeba44 100644 --- a/module/my/view/index.html.php +++ b/module/my/view/index.html.php @@ -1,31 +1,31 @@ - - * @package ZenTaoPMS - * @version $Id: index.html.php 1947 2011-06-29 11:58:03Z wwccss $ - */ -?> - - - - - - - - -
          -
          - -
          - - - - - - -
          - + + * @package ZenTaoPMS + * @version $Id: index.html.php 1947 2011-06-29 11:58:03Z wwccss $ + */ +?> + + + + + + + + +
          +
          + +
          + + + + + + +
          + diff --git a/module/my/view/profile.html.php b/module/my/view/profile.html.php index d14f731242..1c615e7769 100644 --- a/module/my/view/profile.html.php +++ b/module/my/view/profile.html.php @@ -1,120 +1,120 @@ - - * @package my - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          my->profile;?>
          user->dept;?> - $dept) - { - if($dept->name) echo $dept->name; - if(isset($deptPath[$key + 1])) echo $lang->arrow; - } - } - ?> -
          user->account;?>account;?>
          user->realname;?>realname;?>
          user->commiter;?>commiter;?>
          user->email;?>email;?>
          user->join;?>join;?>
          user->visits;?>visits;?>
          user->ip;?>ip;?>
          user->last;?>last;?>
          user->msn;?>msn;?>
          user->qq;?>qq;?>
          user->yahoo;?>yahoo;?>
          user->gtalk;?>gtalk;?>
          user->wangwang;?>wangwang;?>
          user->mobile;?>mobile;?>
          user->phone;?>phone;?>
          user->address;?>address;?>
          user->zipcode;?>zipcode;?>
          - createLink('my', 'editprofile'), $lang->user->editProfile); - echo html::a($this->createLink('user', 'logout'), $lang->logout); - ?> -
          - + + * @package my + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          my->profile;?>
          user->dept;?> + $dept) + { + if($dept->name) echo $dept->name; + if(isset($deptPath[$key + 1])) echo $lang->arrow; + } + } + ?> +
          user->account;?>account;?>
          user->realname;?>realname;?>
          user->commiter;?>commiter;?>
          user->email;?>email;?>
          user->join;?>join;?>
          user->visits;?>visits;?>
          user->ip;?>ip;?>
          user->last;?>last;?>
          user->msn;?>msn;?>
          user->qq;?>qq;?>
          user->yahoo;?>yahoo;?>
          user->gtalk;?>gtalk;?>
          user->wangwang;?>wangwang;?>
          user->mobile;?>mobile;?>
          user->phone;?>phone;?>
          user->address;?>address;?>
          user->zipcode;?>zipcode;?>
          + createLink('my', 'editprofile'), $lang->user->editProfile); + echo html::a($this->createLink('user', 'logout'), $lang->logout); + ?> +
          + diff --git a/module/my/view/project.html.php b/module/my/view/project.html.php index 289a8a0154..e05ec7cf72 100644 --- a/module/my/view/project.html.php +++ b/module/my/view/project.html.php @@ -1,46 +1,46 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - createLink('project', 'browse', "projectID=$project->id");?> - - - - - - - - - - - - - -
          idAB;?>project->code;?>project->name;?>project->begin;?>project->end;?>statusAB;?>team->role;?>team->join;?>team->hours;?>
          id);?>code;?>name);?>begin;?>end;?>project->statusList[$project->status];?>role;?>join;?>hours;?>
          - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + createLink('project', 'browse', "projectID=$project->id");?> + + + + + + + + + + + + + +
          idAB;?>project->code;?>project->name;?>project->begin;?>project->end;?>statusAB;?>team->role;?>team->join;?>team->hours;?>
          id);?>code;?>name);?>begin;?>end;?>project->statusList[$project->status];?>role;?>join;?>hours;?>
          + diff --git a/module/my/view/story.html.php b/module/my/view/story.html.php index 2c396554b6..1066c218c5 100644 --- a/module/my/view/story.html.php +++ b/module/my/view/story.html.php @@ -1,65 +1,65 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          -
          - " . html::a(inlink('story', "type=assignedto"), $lang->my->storyMenu->assignedToMe) . ""; - echo "" . html::a(inlink('story', "type=openedby"), $lang->my->storyMenu->openedByMe) . ""; - echo "" . html::a(inlink('story', "type=reviewedby"), $lang->my->storyMenu->reviewedByMe) . ""; - echo "" . html::a(inlink('story', "type=closedby"), $lang->my->storyMenu->closedByMe) . ""; - ?> -
          -
          - - - - - - - - - - - - - - - - - $story):?> - createLink('story', 'view', "id=$story->id");?> - - - - - - - - - - - - - - -
          idAB;?>priAB;?>story->product;?>story->title;?>story->plan;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions;?>
          id));?>pri;?>productTitle;?>title);?>planTitle;?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> - status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; - if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; - if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; - ?> -
          - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          +
          + " . html::a(inlink('story', "type=assignedto"), $lang->my->storyMenu->assignedToMe) . ""; + echo "" . html::a(inlink('story', "type=openedby"), $lang->my->storyMenu->openedByMe) . ""; + echo "" . html::a(inlink('story', "type=reviewedby"), $lang->my->storyMenu->reviewedByMe) . ""; + echo "" . html::a(inlink('story', "type=closedby"), $lang->my->storyMenu->closedByMe) . ""; + ?> +
          +
          + + + + + + + + + + + + + + + + + $story):?> + createLink('story', 'view', "id=$story->id");?> + + + + + + + + + + + + + + +
          idAB;?>priAB;?>story->product;?>story->title;?>story->plan;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions;?>
          id));?>pri;?>productTitle;?>title);?>planTitle;?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> + status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; + if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; + if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; + ?> +
          + + diff --git a/module/my/view/task.html.php b/module/my/view/task.html.php index 06be12ea41..bc40ecd57e 100644 --- a/module/my/view/task.html.php +++ b/module/my/view/task.html.php @@ -1,82 +1,82 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -
          -
          - " . html::a(inlink('task', "type=assignedto"), $lang->my->taskMenu->assignedToMe) . ""; - echo "" . html::a(inlink('task', "type=openedby"), $lang->my->taskMenu->openedByMe) . ""; - echo "" . html::a(inlink('task', "type=finishedby"), $lang->my->taskMenu->finishedByMe) . ""; - echo "" . html::a(inlink('task', "type=closedby"), $lang->my->taskMenu->closedByMe) . ""; - echo "" . html::a(inlink('task', "type=canceledby"), $lang->my->taskMenu->canceledByMe) . ""; - ?> -
          -
          -
          '> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>priAB;?>task->project;?>task->name;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>openedByAB;?>actions;?>
          - - createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?> - task->priList[$task->pri];?>createLink('project', 'browse', "projectid=$task->projectID"), $task->projectName);?> - createLink('task', 'view', "taskID=$task->id"), $task->name);?>estimate;?>consumed;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>task->statusList[$task->status];?>openedBy];?> - status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; - if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; - if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; - if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; - ?> -
          - selectAll;?> - close)?> -
          -
          - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +
          +
          + " . html::a(inlink('task', "type=assignedto"), $lang->my->taskMenu->assignedToMe) . ""; + echo "" . html::a(inlink('task', "type=openedby"), $lang->my->taskMenu->openedByMe) . ""; + echo "" . html::a(inlink('task', "type=finishedby"), $lang->my->taskMenu->finishedByMe) . ""; + echo "" . html::a(inlink('task', "type=closedby"), $lang->my->taskMenu->closedByMe) . ""; + echo "" . html::a(inlink('task', "type=canceledby"), $lang->my->taskMenu->canceledByMe) . ""; + ?> +
          +
          +
          '> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>priAB;?>task->project;?>task->name;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>openedByAB;?>actions;?>
          + + createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?> + task->priList[$task->pri];?>createLink('project', 'browse', "projectid=$task->projectID"), $task->projectName);?> + createLink('task', 'view', "taskID=$task->id"), $task->name);?>estimate;?>consumed;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>task->statusList[$task->status];?>openedBy];?> + status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; + if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; + if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; + if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; + ?> +
          + selectAll;?> + close)?> +
          +
          + diff --git a/module/my/view/team.html.php b/module/my/view/team.html.php index 7030b367d6..95c5ad5ce6 100644 --- a/module/my/view/team.html.php +++ b/module/my/view/team.html.php @@ -1,14 +1,14 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + diff --git a/module/my/view/testcase.html.php b/module/my/view/testcase.html.php index 78d7afc3ad..9831605841 100644 --- a/module/my/view/testcase.html.php +++ b/module/my/view/testcase.html.php @@ -1,59 +1,59 @@ - - * @package dashboard - * @version $Id: test.html.php 1191 2010-11-13 07:30:35Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - -
          -
          - " . html::a($this->createLink('my', 'testtask'), $lang->my->testTask) . ""; - echo "" . html::a($this->createLink('my', 'testcase', "type=assigntome"), $lang->testcase->assignToMe) . ""; - //echo "" . html::a($this->createLink('my', 'testcase', "type=donebyme"), $lang->testcase->doneByMe) . ""; - echo "" . html::a($this->createLink('my', 'testcase', "type=openedbyme"), $lang->testcase->openedByMe) . ""; - ?> -
          -
          - -recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>priAB;?>testcase->title;?> typeAB;?> openedByAB;?>statusAB;?>actions;?>
          createLink('testcase', 'view', "testcaseID=$case->id"), sprintf('%03d', $case->id));?>pri?>createLink('testcase', 'view', "testcaseID=$case->id"), $case->title);?>testcase->typeList[$case->type];?>openedBy];?>testcase->statusList[$case->status];?> - id", $lang->testcase->buttonEdit); - ?> -
          show();?>
          - - + + * @package dashboard + * @version $Id: test.html.php 1191 2010-11-13 07:30:35Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + +
          +
          + " . html::a($this->createLink('my', 'testtask'), $lang->my->testTask) . ""; + echo "" . html::a($this->createLink('my', 'testcase', "type=assigntome"), $lang->testcase->assignToMe) . ""; + //echo "" . html::a($this->createLink('my', 'testcase', "type=donebyme"), $lang->testcase->doneByMe) . ""; + echo "" . html::a($this->createLink('my', 'testcase', "type=openedbyme"), $lang->testcase->openedByMe) . ""; + ?> +
          +
          + +recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>priAB;?>testcase->title;?> typeAB;?> openedByAB;?>statusAB;?>actions;?>
          createLink('testcase', 'view', "testcaseID=$case->id"), sprintf('%03d', $case->id));?>pri?>createLink('testcase', 'view', "testcaseID=$case->id"), $case->title);?>testcase->typeList[$case->type];?>openedBy];?>testcase->statusList[$case->status];?> + id", $lang->testcase->buttonEdit); + ?> +
          show();?>
          + + diff --git a/module/my/view/testtask.html.php b/module/my/view/testtask.html.php index 2a861cccf1..1a5965af00 100644 --- a/module/my/view/testtask.html.php +++ b/module/my/view/testtask.html.php @@ -1,60 +1,60 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          -
          - " . html::a($this->createLink('my', 'testtask'), $lang->my->testTask) . ""; - echo "" . html::a($this->createLink('my', 'testcase', "type=assigntome"), $lang->testcase->assignToMe) . ""; - //echo "" . html::a($this->createLink('my', 'testcase', "type=donebyme"), $lang->testcase->doneByMe) . ""; - echo "" . html::a($this->createLink('my', 'testcase', "type=openedbyme"), $lang->testcase->openedByMe) . ""; - ?> -
          -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>testtask->name;?>testtask->project;?>testtask->build;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          createLink('testtask', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>createLink('testtask', 'view', "taskID=$task->id"), $task->name);?>projectName?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>begin?>end?>testtask->statusList[$task->status];?> - id", $lang->testtask->cases); - common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); - common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); - ?> -
          - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          +
          + " . html::a($this->createLink('my', 'testtask'), $lang->my->testTask) . ""; + echo "" . html::a($this->createLink('my', 'testcase', "type=assigntome"), $lang->testcase->assignToMe) . ""; + //echo "" . html::a($this->createLink('my', 'testcase', "type=donebyme"), $lang->testcase->doneByMe) . ""; + echo "" . html::a($this->createLink('my', 'testcase', "type=openedbyme"), $lang->testcase->openedByMe) . ""; + ?> +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>testtask->name;?>testtask->project;?>testtask->build;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          createLink('testtask', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>createLink('testtask', 'view', "taskID=$task->id"), $task->name);?>projectName?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>begin?>end?>testtask->statusList[$task->status];?> + id", $lang->testtask->cases); + common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); + common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); + ?> +
          + + diff --git a/module/my/view/todo.html.php b/module/my/view/todo.html.php index 3b0254d098..b54a91f7f0 100644 --- a/module/my/view/todo.html.php +++ b/module/my/view/todo.html.php @@ -1,89 +1,89 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          ' id='todoform'> -
          -
          - ' . html::a(inlink('todo', "date=today"), $lang->todo->todayTodos) . ''; - echo '' . html::a(inlink('todo', "date=thisweek"), $lang->todo->thisWeekTodos) . ''; - echo '' . html::a(inlink('todo', "date=lastweek"), $lang->todo->lastWeekTodos) . ''; - echo '' . html::a(inlink('todo', "date=future"), $lang->todo->futureTodos) . ''; - echo '' . html::a(inlink('todo', "date=all"), $lang->todo->allDaysTodos) . ''; - echo '' . html::a(inlink('todo', "date=before&account={$app->user->account}&status=undone"), $lang->todo->allUndone) . ''; - echo "" . html::select('date', $dates, $date, 'onchange=changeDate(this.value)') . ''; - ?> - -
          -
          - export, '', 'class="export"'); - echo html::a($this->createLink('todo', 'create', "date=$date"), $lang->todo->create); - ?> -
          -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>todo->date;?>todo->type;?>priAB;?>todo->name;?>todo->beginAB;?>todo->endAB;?>todo->status;?>actions;?>
          - id' /> "; - echo $todo->id; - ?> - date == '2030-01-01' ? $lang->todo->dayInFuture : $todo->date;?>todo->typeList->{$todo->type};?>pri;?>createLink('todo', 'view', "id=$todo->id&from=my"), $todo->name);?>begin;?>end;?>todo->statusList[$todo->status];?> - createLink('todo', 'mark', "id=$todo->id&status=$todo->status"), $lang->todo->{'mark'.ucfirst($todo->status)}, 'hiddenwin'); - echo html::a($this->createLink('todo', 'view', "id=$todo->id&from=my"), $lang->todo->viewAB); - echo html::a($this->createLink('todo', 'edit', "id=$todo->id"), $lang->edit); - echo html::a($this->createLink('todo', 'delete', "id=$todo->id"), $lang->delete, 'hiddenwin'); - ?> -
          - -
          -
          - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          ' id='todoform'> +
          +
          + ' . html::a(inlink('todo', "date=today"), $lang->todo->todayTodos) . ''; + echo '' . html::a(inlink('todo', "date=thisweek"), $lang->todo->thisWeekTodos) . ''; + echo '' . html::a(inlink('todo', "date=lastweek"), $lang->todo->lastWeekTodos) . ''; + echo '' . html::a(inlink('todo', "date=future"), $lang->todo->futureTodos) . ''; + echo '' . html::a(inlink('todo', "date=all"), $lang->todo->allDaysTodos) . ''; + echo '' . html::a(inlink('todo', "date=before&account={$app->user->account}&status=undone"), $lang->todo->allUndone) . ''; + echo "" . html::select('date', $dates, $date, 'onchange=changeDate(this.value)') . ''; + ?> + +
          +
          + export, '', 'class="export"'); + echo html::a($this->createLink('todo', 'create', "date=$date"), $lang->todo->create); + ?> +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>todo->date;?>todo->type;?>priAB;?>todo->name;?>todo->beginAB;?>todo->endAB;?>todo->status;?>actions;?>
          + id' /> "; + echo $todo->id; + ?> + date == '2030-01-01' ? $lang->todo->dayInFuture : $todo->date;?>todo->typeList->{$todo->type};?>pri;?>createLink('todo', 'view', "id=$todo->id&from=my"), $todo->name);?>begin;?>end;?>todo->statusList[$todo->status];?> + createLink('todo', 'mark', "id=$todo->id&status=$todo->status"), $lang->todo->{'mark'.ucfirst($todo->status)}, 'hiddenwin'); + echo html::a($this->createLink('todo', 'view', "id=$todo->id&from=my"), $lang->todo->viewAB); + echo html::a($this->createLink('todo', 'edit', "id=$todo->id"), $lang->edit); + echo html::a($this->createLink('todo', 'delete', "id=$todo->id"), $lang->delete, 'hiddenwin'); + ?> +
          + +
          +
          + diff --git a/module/product/control.php b/module/product/control.php index 0f55d60157..84c01b0177 100644 --- a/module/product/control.php +++ b/module/product/control.php @@ -1,399 +1,399 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -class product extends control -{ - private $products = array(); - - /** - * Construct function. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - - /* Load need modules. */ - $this->loadModel('story'); - $this->loadModel('release'); - $this->loadModel('tree'); - $this->loadModel('user'); - - /* Get all products, if no, goto the create page. */ - $this->products = $this->product->getPairs(); - if(empty($this->products) and strpos('create', $this->methodName) === false) $this->locate($this->createLink('product', 'create')); - $this->view->products = $this->products; - } - - /** - * Index page, to browse. - * - * @access public - * @return void - */ - public function index($locate = 'yes') - { - if($locate == 'yes') $this->locate($this->createLink($this->moduleName, 'browse')); - - $this->app->loadLang('my'); - $this->view->productStats = $this->product->getStats(); - $this->display(); - } - - /** - * project - * - * @param string $status - * @param int $productID - * @access public - * @return void - */ - public function project($status = 'all', $productID = 0) - { - $this->app->loadLang('my'); - $this->view->projectStats = $this->loadModel('project')->getProjectStats($status, $productID); - - $this->view->productID = $productID; - $this->display(); - } - - /** - * Browse a product. - * - * @param int $productID - * @param string $browseType - * @param int $param - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Lower browse type. */ - $browseType = strtolower($browseType); - - /* Save session. */ - $this->session->set('storyList', $this->app->getURI(true)); - $this->session->set('productList', $this->app->getURI(true)); - - /* Set product, module and query. */ - $productID = $this->product->saveState($productID, $this->products); - $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Set menu. */ - $this->product->setMenu($this->products, $productID); - - /* Process the order by field. */ - if(!$orderBy) $orderBy = $this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc'; - setcookie('productStoryOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); - - /* Set header and position. */ - $this->view->header->title = $this->lang->product->index . $this->lang->colon . $this->products[$productID]; - $this->view->position[] = $this->products[$productID]; - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); - - /* Get stories. */ - $stories = array(); - if($browseType == 'allstory') $stories = $this->story->getProductStories($productID, 0, 'all', $orderBy, $pager); - if($browseType == 'bymodule') $stories = $this->story->getProductStories($productID, $this->tree->getAllChildID($moduleID), 'all', $orderBy, $pager); - if($browseType == 'bysearch') $stories = $this->story->getBySearch($productID, $queryID, $orderBy, $pager); - if($browseType == 'assignedtome')$stories = $this->story->getByAssignedTo($productID, $this->app->user->account, $orderBy, $pager); - if($browseType == 'openedbyme') $stories = $this->story->getByOpenedBy($productID, $this->app->user->account, $orderBy, $pager); - if($browseType == 'reviewedbyme')$stories = $this->story->getByReviewedBy($productID, $this->app->user->account, $orderBy, $pager); - if($browseType == 'closedbyme') $stories = $this->story->getByClosedBy($productID, $this->app->user->account, $orderBy, $pager); - if($browseType == 'draftstory') $stories = $this->story->getByStatus($productID, 'draft', $orderBy, $pager); - if($browseType == 'activestory') $stories = $this->story->getByStatus($productID, 'active', $orderBy, $pager); - if($browseType == 'changedstory')$stories = $this->story->getByStatus($productID, 'changed', $orderBy, $pager); - if($browseType == 'closedstory') $stories = $this->story->getByStatus($productID, 'closed', $orderBy, $pager); - - /* Build search form. */ - $this->config->product->search['actionURL'] = $this->createLink('product', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); - $this->config->product->search['queryID'] = $queryID; - $this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs($productID); - $this->config->product->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->product->allProduct); - $this->config->product->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'story', $startModuleID = 0); - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->product->search); - - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleID = $moduleID; - $this->view->stories = $stories; - $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'story', $startModuleID = 0, array('treeModel', 'createStoryLink')); - $this->view->parentModules = $this->tree->getParents($moduleID); - $this->view->pager = $pager; - $this->view->users = $this->user->getPairs('noletter'); - $this->view->orderBy = $orderBy; - $this->view->browseType = $browseType; - $this->view->moduleID = $moduleID; - $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; - $this->display(); - } - - /** - * Create a product. - * - * @access public - * @return void - */ - public function create() - { - if(!empty($_POST)) - { - $productID = $this->product->create(); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('product', $productID, 'opened'); - die(js::locate($this->createLink($this->moduleName, 'browse', "productID=$productID"), 'parent')); - } - - $this->product->setMenu($this->products, key($this->products)); - - $this->view->header->title = $this->lang->product->create; - $this->view->position[] = $this->view->header->title; - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->users = $this->loadModel('user')->getPairs(); - $this->display(); - } - - /** - * Edit a product. - * - * @param int $productID - * @access public - * @return void - */ - public function edit($productID) - { - if(!empty($_POST)) - { - $changes = $this->product->update($productID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('product', $productID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "product=$productID"), 'parent')); - } - - $this->product->setMenu($this->products, $productID); - - $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); - $this->view->header->title = $this->lang->product->edit . $this->lang->colon . $product->name; - $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); - $this->view->position[] = $this->lang->product->edit; - $this->view->product = $product; - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->users = $this->loadModel('user')->getPairs(); - - $this->display(); - } - - /** - * View a product. - * - * @param int $productID - * @access public - * @return void - */ - public function view($productID) - { - $this->product->setMenu($this->products, $productID); - - $product = $this->product->getStatByID($productID); - $product->desc = $this->loadModel('file')->setImgSize($product->desc); - if(!$product) die(js::error($this->lang->notFound) . js::locate('back')); - - $this->view->header->title = $this->lang->product->view . $this->lang->colon . $product->name; - $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); - $this->view->position[] = $this->lang->product->view; - $this->view->product = $product; - $this->view->actions = $this->loadModel('action')->getList('product', $productID); - $this->view->users = $this->user->getPairs('noletter'); - $this->view->groups = $this->loadModel('group')->getPairs(); - - $this->display(); - } - - /** - * Delete a product. - * - * @param int $productID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($productID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->product->confirmDelete, $this->createLink('product', 'delete', "productID=$productID&confirm=yes"))); - } - else - { - $this->product->delete(TABLE_PRODUCT, $productID); - $this->session->set('product', ''); // 清除session。 - die(js::locate($this->createLink('product', 'browse'), 'parent')); - } - } - - /** - * Docs of a product. - * - * @param int $productID - * @access public - * @return void - */ - public function doc($productID) - { - $this->product->setMenu($this->products, $productID); - $this->session->set('docList', $this->app->getURI(true)); - - $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); - $this->view->header->title = $this->lang->product->doc; - $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); - $this->view->position[] = $this->lang->product->doc; - $this->view->product = $product; - $this->view->docs = $this->loadModel('doc')->getProductDocs($productID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Road map of a product. - * - * @param int $productID - * @access public - * @return void - */ - public function roadmap($productID) - { - $this->product->setMenu($this->products, $productID); - - $this->session->set('releaseList', $this->app->getURI(true)); - $this->session->set('productPlanList', $this->app->getURI(true)); - - $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); - $this->view->header->title = $this->lang->product->roadmap; - $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); - $this->view->position[] = $this->lang->product->roadmap; - $this->view->product = $product; - $this->view->roadmaps = $this->product->getRoadmap($productID); - - $this->display(); - } - - /** - * Product dynamic. - * - * @param string $type - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function dynamic($productID = 0, $type = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - $this->product->setMenu($this->products, $productID); - - /* Set the pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - - /* Set the user and type. */ - $account = $type == 'account' ? $param : 'all'; - $period = $type == 'account' ? 'all' : $type; - - /* The header and position. */ - $this->view->header->title = $this->lang->product->dynamic; - $this->view->position[] = $this->lang->product->dynamic; - - /* Assign. */ - $this->view->productID = $productID; - $this->view->type = $type; - $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); - $this->view->account = $account; - $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager, $productID); - $this->display(); - } - - /** - * order product - * - * @param int $productID - * @access public - * @return void - */ - public function order($productID) - { - if($_POST) - { - $this->product->saveOrder(); - die(js::reload('parent')); - } - $this->product->setMenu($this->products, $productID); - $this->view->products = $this->product->getList('noclosed'); - $this->display(); - } - - /** - * AJAX: get projects of a product in html select. - * - * @param int $productID - * @param int $projectID - * @access public - * @return void - */ - public function ajaxGetProjects($productID, $projectID = 0) - { - $projects = $this->product->getProjectPairs($productID); - die(html::select('project', $projects, $projectID, 'onchange=loadProjectRelated(this.value)')); - } - - /** - * AJAX: get plans of a product in html select. - * - * @param int $productID - * @param int $planID - * @access public - * @return void - */ - public function ajaxGetPlans($productID, $planID = 0) - { - $plans = $this->loadModel('productplan')->getPairs($productID); - die(html::select('plan', $plans, $planID)); - } -} + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +class product extends control +{ + private $products = array(); + + /** + * Construct function. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + + /* Load need modules. */ + $this->loadModel('story'); + $this->loadModel('release'); + $this->loadModel('tree'); + $this->loadModel('user'); + + /* Get all products, if no, goto the create page. */ + $this->products = $this->product->getPairs(); + if(empty($this->products) and strpos('create', $this->methodName) === false) $this->locate($this->createLink('product', 'create')); + $this->view->products = $this->products; + } + + /** + * Index page, to browse. + * + * @access public + * @return void + */ + public function index($locate = 'yes') + { + if($locate == 'yes') $this->locate($this->createLink($this->moduleName, 'browse')); + + $this->app->loadLang('my'); + $this->view->productStats = $this->product->getStats(); + $this->display(); + } + + /** + * project + * + * @param string $status + * @param int $productID + * @access public + * @return void + */ + public function project($status = 'all', $productID = 0) + { + $this->app->loadLang('my'); + $this->view->projectStats = $this->loadModel('project')->getProjectStats($status, $productID); + + $this->view->productID = $productID; + $this->display(); + } + + /** + * Browse a product. + * + * @param int $productID + * @param string $browseType + * @param int $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Lower browse type. */ + $browseType = strtolower($browseType); + + /* Save session. */ + $this->session->set('storyList', $this->app->getURI(true)); + $this->session->set('productList', $this->app->getURI(true)); + + /* Set product, module and query. */ + $productID = $this->product->saveState($productID, $this->products); + $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Set menu. */ + $this->product->setMenu($this->products, $productID); + + /* Process the order by field. */ + if(!$orderBy) $orderBy = $this->cookie->productStoryOrder ? $this->cookie->productStoryOrder : 'id_desc'; + setcookie('productStoryOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); + + /* Set header and position. */ + $this->view->header->title = $this->lang->product->index . $this->lang->colon . $this->products[$productID]; + $this->view->position[] = $this->products[$productID]; + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + /* Get stories. */ + $stories = array(); + if($browseType == 'allstory') $stories = $this->story->getProductStories($productID, 0, 'all', $orderBy, $pager); + if($browseType == 'bymodule') $stories = $this->story->getProductStories($productID, $this->tree->getAllChildID($moduleID), 'all', $orderBy, $pager); + if($browseType == 'bysearch') $stories = $this->story->getBySearch($productID, $queryID, $orderBy, $pager); + if($browseType == 'assignedtome')$stories = $this->story->getByAssignedTo($productID, $this->app->user->account, $orderBy, $pager); + if($browseType == 'openedbyme') $stories = $this->story->getByOpenedBy($productID, $this->app->user->account, $orderBy, $pager); + if($browseType == 'reviewedbyme')$stories = $this->story->getByReviewedBy($productID, $this->app->user->account, $orderBy, $pager); + if($browseType == 'closedbyme') $stories = $this->story->getByClosedBy($productID, $this->app->user->account, $orderBy, $pager); + if($browseType == 'draftstory') $stories = $this->story->getByStatus($productID, 'draft', $orderBy, $pager); + if($browseType == 'activestory') $stories = $this->story->getByStatus($productID, 'active', $orderBy, $pager); + if($browseType == 'changedstory')$stories = $this->story->getByStatus($productID, 'changed', $orderBy, $pager); + if($browseType == 'closedstory') $stories = $this->story->getByStatus($productID, 'closed', $orderBy, $pager); + + /* Build search form. */ + $this->config->product->search['actionURL'] = $this->createLink('product', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); + $this->config->product->search['queryID'] = $queryID; + $this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs($productID); + $this->config->product->search['params']['product']['values'] = array($productID => $this->products[$productID], 'all' => $this->lang->product->allProduct); + $this->config->product->search['params']['module']['values'] = $this->tree->getOptionMenu($productID, $viewType = 'story', $startModuleID = 0); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->product->search); + + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleID = $moduleID; + $this->view->stories = $stories; + $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'story', $startModuleID = 0, array('treeModel', 'createStoryLink')); + $this->view->parentModules = $this->tree->getParents($moduleID); + $this->view->pager = $pager; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->moduleID = $moduleID; + $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; + $this->display(); + } + + /** + * Create a product. + * + * @access public + * @return void + */ + public function create() + { + if(!empty($_POST)) + { + $productID = $this->product->create(); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('product', $productID, 'opened'); + die(js::locate($this->createLink($this->moduleName, 'browse', "productID=$productID"), 'parent')); + } + + $this->product->setMenu($this->products, key($this->products)); + + $this->view->header->title = $this->lang->product->create; + $this->view->position[] = $this->view->header->title; + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->display(); + } + + /** + * Edit a product. + * + * @param int $productID + * @access public + * @return void + */ + public function edit($productID) + { + if(!empty($_POST)) + { + $changes = $this->product->update($productID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('product', $productID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "product=$productID"), 'parent')); + } + + $this->product->setMenu($this->products, $productID); + + $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); + $this->view->header->title = $this->lang->product->edit . $this->lang->colon . $product->name; + $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); + $this->view->position[] = $this->lang->product->edit; + $this->view->product = $product; + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->users = $this->loadModel('user')->getPairs(); + + $this->display(); + } + + /** + * View a product. + * + * @param int $productID + * @access public + * @return void + */ + public function view($productID) + { + $this->product->setMenu($this->products, $productID); + + $product = $this->product->getStatByID($productID); + $product->desc = $this->loadModel('file')->setImgSize($product->desc); + if(!$product) die(js::error($this->lang->notFound) . js::locate('back')); + + $this->view->header->title = $this->lang->product->view . $this->lang->colon . $product->name; + $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); + $this->view->position[] = $this->lang->product->view; + $this->view->product = $product; + $this->view->actions = $this->loadModel('action')->getList('product', $productID); + $this->view->users = $this->user->getPairs('noletter'); + $this->view->groups = $this->loadModel('group')->getPairs(); + + $this->display(); + } + + /** + * Delete a product. + * + * @param int $productID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($productID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->product->confirmDelete, $this->createLink('product', 'delete', "productID=$productID&confirm=yes"))); + } + else + { + $this->product->delete(TABLE_PRODUCT, $productID); + $this->session->set('product', ''); // 清除session。 + die(js::locate($this->createLink('product', 'browse'), 'parent')); + } + } + + /** + * Docs of a product. + * + * @param int $productID + * @access public + * @return void + */ + public function doc($productID) + { + $this->product->setMenu($this->products, $productID); + $this->session->set('docList', $this->app->getURI(true)); + + $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); + $this->view->header->title = $this->lang->product->doc; + $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); + $this->view->position[] = $this->lang->product->doc; + $this->view->product = $product; + $this->view->docs = $this->loadModel('doc')->getProductDocs($productID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Road map of a product. + * + * @param int $productID + * @access public + * @return void + */ + public function roadmap($productID) + { + $this->product->setMenu($this->products, $productID); + + $this->session->set('releaseList', $this->app->getURI(true)); + $this->session->set('productPlanList', $this->app->getURI(true)); + + $product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); + $this->view->header->title = $this->lang->product->roadmap; + $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); + $this->view->position[] = $this->lang->product->roadmap; + $this->view->product = $product; + $this->view->roadmaps = $this->product->getRoadmap($productID); + + $this->display(); + } + + /** + * Product dynamic. + * + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dynamic($productID = 0, $type = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + $this->product->setMenu($this->products, $productID); + + /* Set the pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + + /* Set the user and type. */ + $account = $type == 'account' ? $param : 'all'; + $period = $type == 'account' ? 'all' : $type; + + /* The header and position. */ + $this->view->header->title = $this->lang->product->dynamic; + $this->view->position[] = $this->lang->product->dynamic; + + /* Assign. */ + $this->view->productID = $productID; + $this->view->type = $type; + $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); + $this->view->account = $account; + $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager, $productID); + $this->display(); + } + + /** + * order product + * + * @param int $productID + * @access public + * @return void + */ + public function order($productID) + { + if($_POST) + { + $this->product->saveOrder(); + die(js::reload('parent')); + } + $this->product->setMenu($this->products, $productID); + $this->view->products = $this->product->getList('noclosed'); + $this->display(); + } + + /** + * AJAX: get projects of a product in html select. + * + * @param int $productID + * @param int $projectID + * @access public + * @return void + */ + public function ajaxGetProjects($productID, $projectID = 0) + { + $projects = $this->product->getProjectPairs($productID); + die(html::select('project', $projects, $projectID, 'onchange=loadProjectRelated(this.value)')); + } + + /** + * AJAX: get plans of a product in html select. + * + * @param int $productID + * @param int $planID + * @access public + * @return void + */ + public function ajaxGetPlans($productID, $planID = 0) + { + $plans = $this->loadModel('productplan')->getPairs($productID); + die(html::select('plan', $plans, $planID)); + } +} diff --git a/module/product/lang/en.php b/module/product/lang/en.php index 9012c77b7d..ef8471167b 100644 --- a/module/product/lang/en.php +++ b/module/product/lang/en.php @@ -1,84 +1,84 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->product->common = 'Product'; -$lang->product->index = "Index"; -$lang->product->browse = "Browse"; -$lang->product->dynamic= "Dynamic"; -$lang->product->view = "Info"; -$lang->product->edit = "Edit"; -$lang->product->create = "Create"; -$lang->product->read = "Info"; -$lang->product->delete = "Delete"; -$lang->product->select = '--select product--'; - -$lang->product->basicInfo = 'Basic info'; -$lang->product->otherInfo = 'Other info'; - -$lang->product->plans = 'Plans'; -$lang->product->releases = 'Releases'; -$lang->product->docs = 'Documents'; -$lang->product->bugs = 'Bugs'; -$lang->product->projects = 'Projects'; -$lang->product->cases = 'Cases'; -$lang->product->bulids = 'Bulids'; -$lang->product->roadmap = 'Roadmap'; -$lang->product->doc = 'Doc'; -$lang->product->project = 'Projects'; - -$lang->product->selectProduct = "Select product"; -$lang->product->saveButton = " Save (S) "; -$lang->product->confirmDelete = " Are you sure to delete this product?"; -$lang->product->ajaxGetProjects = "API: projects of product"; -$lang->product->ajaxGetPlans = "API: plans of product"; - -$lang->product->errorFormat = 'Error format.'; -$lang->product->errorEmptyName = 'Name can not be empty.'; -$lang->product->errorEmptyCode = 'Code can not be empty'; -$lang->product->errorNoProduct = 'No product in system yet.'; -$lang->product->accessDenied = 'Access to this product denined.'; - -$lang->product->id = 'ID'; -$lang->product->company = 'Company'; -$lang->product->name = 'Name'; -$lang->product->code = 'Code'; -$lang->product->order = 'Order'; -$lang->product->status = 'Status'; -$lang->product->desc = 'Desc'; -$lang->product->PO = 'Product owner'; -$lang->product->QM = 'Test manager'; -$lang->product->RM = 'Release manager'; -$lang->product->acl = 'Access limitation'; -$lang->product->whitelist = 'Whitelist'; - -$lang->product->moduleStory = 'By module'; -$lang->product->searchStory = 'By search'; -$lang->product->assignedToMe = 'To me'; -$lang->product->openedByMe = 'Opened by me'; -$lang->product->reviewedByMe = 'Reviewed by me'; -$lang->product->closedByMe = 'Closed by me'; -$lang->product->draftStory = 'Draft story'; -$lang->product->activeStory = 'Active story'; -$lang->product->changedStory = 'Changed story'; -$lang->product->closedStory = 'Closed story'; - -$lang->product->allStory = 'All story'; -$lang->product->allProduct = 'All products'; - -$lang->product->statusList[''] = ''; -$lang->product->statusList['normal'] = 'Normal'; -$lang->product->statusList['closed'] = 'Closed'; - -$lang->product->aclList['open'] = 'Default(Having product module prividge, can visit this product)'; -$lang->product->aclList['private'] = 'Private(Only project team members can visit)'; -$lang->product->aclList['custom'] = 'Whitelist(Project team members and who belongs to the whilelist groups can visit)'; - -$lang->product->storySummary = "Total %s stories in this page, estimate %s hours."; + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->product->common = 'Product'; +$lang->product->index = "Index"; +$lang->product->browse = "Browse"; +$lang->product->dynamic= "Dynamic"; +$lang->product->view = "Info"; +$lang->product->edit = "Edit"; +$lang->product->create = "Create"; +$lang->product->read = "Info"; +$lang->product->delete = "Delete"; +$lang->product->select = '--select product--'; + +$lang->product->basicInfo = 'Basic info'; +$lang->product->otherInfo = 'Other info'; + +$lang->product->plans = 'Plans'; +$lang->product->releases = 'Releases'; +$lang->product->docs = 'Documents'; +$lang->product->bugs = 'Bugs'; +$lang->product->projects = 'Projects'; +$lang->product->cases = 'Cases'; +$lang->product->bulids = 'Bulids'; +$lang->product->roadmap = 'Roadmap'; +$lang->product->doc = 'Doc'; +$lang->product->project = 'Projects'; + +$lang->product->selectProduct = "Select product"; +$lang->product->saveButton = " Save (S) "; +$lang->product->confirmDelete = " Are you sure to delete this product?"; +$lang->product->ajaxGetProjects = "API: projects of product"; +$lang->product->ajaxGetPlans = "API: plans of product"; + +$lang->product->errorFormat = 'Error format.'; +$lang->product->errorEmptyName = 'Name can not be empty.'; +$lang->product->errorEmptyCode = 'Code can not be empty'; +$lang->product->errorNoProduct = 'No product in system yet.'; +$lang->product->accessDenied = 'Access to this product denined.'; + +$lang->product->id = 'ID'; +$lang->product->company = 'Company'; +$lang->product->name = 'Name'; +$lang->product->code = 'Code'; +$lang->product->order = 'Order'; +$lang->product->status = 'Status'; +$lang->product->desc = 'Desc'; +$lang->product->PO = 'Product owner'; +$lang->product->QM = 'Test manager'; +$lang->product->RM = 'Release manager'; +$lang->product->acl = 'Access limitation'; +$lang->product->whitelist = 'Whitelist'; + +$lang->product->moduleStory = 'By module'; +$lang->product->searchStory = 'By search'; +$lang->product->assignedToMe = 'To me'; +$lang->product->openedByMe = 'Opened by me'; +$lang->product->reviewedByMe = 'Reviewed by me'; +$lang->product->closedByMe = 'Closed by me'; +$lang->product->draftStory = 'Draft story'; +$lang->product->activeStory = 'Active story'; +$lang->product->changedStory = 'Changed story'; +$lang->product->closedStory = 'Closed story'; + +$lang->product->allStory = 'All story'; +$lang->product->allProduct = 'All products'; + +$lang->product->statusList[''] = ''; +$lang->product->statusList['normal'] = 'Normal'; +$lang->product->statusList['closed'] = 'Closed'; + +$lang->product->aclList['open'] = 'Default(Having product module prividge, can visit this product)'; +$lang->product->aclList['private'] = 'Private(Only project team members can visit)'; +$lang->product->aclList['custom'] = 'Whitelist(Project team members and who belongs to the whilelist groups can visit)'; + +$lang->product->storySummary = "Total %s stories in this page, estimate %s hours."; diff --git a/module/product/lang/zh-cn.php b/module/product/lang/zh-cn.php index bd1059c868..080a3c62fb 100644 --- a/module/product/lang/zh-cn.php +++ b/module/product/lang/zh-cn.php @@ -1,84 +1,84 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->product->common = '产品视图'; -$lang->product->index = "产品首页"; -$lang->product->browse = "浏览产品"; -$lang->product->dynamic= "动态"; -$lang->product->view = "产品信息"; -$lang->product->edit = "编辑产品"; -$lang->product->create = "新增产品"; -$lang->product->read = "产品详情"; -$lang->product->delete = "删除产品"; -$lang->product->select = '--请选择产品--'; - -$lang->product->basicInfo = '基本信息'; -$lang->product->otherInfo = '其他信息'; - -$lang->product->plans = '计划数'; -$lang->product->releases = '发布数'; -$lang->product->docs = '文档数'; -$lang->product->bugs = '相关BUG'; -$lang->product->projects = '关联项目数'; -$lang->product->cases = '用例数'; -$lang->product->bulids = 'BULID数'; -$lang->product->roadmap = '路线图'; -$lang->product->doc = '文档列表'; -$lang->product->project = '项目列表'; - -$lang->product->selectProduct = "请选择产品"; -$lang->product->saveButton = " 保存 (S) "; -$lang->product->confirmDelete = " 您确定删除该产品吗?"; -$lang->product->ajaxGetProjects = "接口:项目列表"; -$lang->product->ajaxGetPlans = "接口:计划列表"; - -$lang->product->errorFormat = '产品数据格式不正确'; -$lang->product->errorEmptyName = '产品名称不能为空'; -$lang->product->errorEmptyCode = '产品代号不能为空'; -$lang->product->errorNoProduct = '还没有创建产品!'; -$lang->product->accessDenied = '您无权访问该产品'; - -$lang->product->id = '编号'; -$lang->product->company = '所属公司'; -$lang->product->name = '产品名称'; -$lang->product->code = '产品代号'; -$lang->product->order = '排序'; -$lang->product->status = '状态'; -$lang->product->desc = '产品描述'; -$lang->product->PO = '产品负责人'; -$lang->product->QM = '测试负责人'; -$lang->product->RM = '发布负责人'; -$lang->product->acl = '访问控制'; -$lang->product->whitelist = '分组白名单'; - -$lang->product->moduleStory = '按模块浏览'; -$lang->product->searchStory = '搜索'; -$lang->product->assignedToMe = '指派给我'; -$lang->product->openedByMe = '由我创建'; -$lang->product->reviewedByMe = '由我评审'; -$lang->product->closedByMe = '由我关闭'; -$lang->product->draftStory = '草稿'; -$lang->product->activeStory = '激活'; -$lang->product->changedStory = '已变更'; -$lang->product->closedStory = '已关闭'; - -$lang->product->allStory = '全部需求'; -$lang->product->allProduct = '全部产品'; - -$lang->product->statusList[''] = ''; -$lang->product->statusList['normal'] = '正常'; -$lang->product->statusList['closed'] = '结束'; - -$lang->product->aclList['open'] = '默认设置(有产品视图权限,即可访问)'; -$lang->product->aclList['private'] = '私有项目(只有项目团队成员才能访问)'; -$lang->product->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)'; - -$lang->product->storySummary = "本页共 %s 个需求,预计 %s 个工时。"; + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->product->common = '产品视图'; +$lang->product->index = "产品首页"; +$lang->product->browse = "浏览产品"; +$lang->product->dynamic= "动态"; +$lang->product->view = "产品信息"; +$lang->product->edit = "编辑产品"; +$lang->product->create = "新增产品"; +$lang->product->read = "产品详情"; +$lang->product->delete = "删除产品"; +$lang->product->select = '--请选择产品--'; + +$lang->product->basicInfo = '基本信息'; +$lang->product->otherInfo = '其他信息'; + +$lang->product->plans = '计划数'; +$lang->product->releases = '发布数'; +$lang->product->docs = '文档数'; +$lang->product->bugs = '相关BUG'; +$lang->product->projects = '关联项目数'; +$lang->product->cases = '用例数'; +$lang->product->bulids = 'BULID数'; +$lang->product->roadmap = '路线图'; +$lang->product->doc = '文档列表'; +$lang->product->project = '项目列表'; + +$lang->product->selectProduct = "请选择产品"; +$lang->product->saveButton = " 保存 (S) "; +$lang->product->confirmDelete = " 您确定删除该产品吗?"; +$lang->product->ajaxGetProjects = "接口:项目列表"; +$lang->product->ajaxGetPlans = "接口:计划列表"; + +$lang->product->errorFormat = '产品数据格式不正确'; +$lang->product->errorEmptyName = '产品名称不能为空'; +$lang->product->errorEmptyCode = '产品代号不能为空'; +$lang->product->errorNoProduct = '还没有创建产品!'; +$lang->product->accessDenied = '您无权访问该产品'; + +$lang->product->id = '编号'; +$lang->product->company = '所属公司'; +$lang->product->name = '产品名称'; +$lang->product->code = '产品代号'; +$lang->product->order = '排序'; +$lang->product->status = '状态'; +$lang->product->desc = '产品描述'; +$lang->product->PO = '产品负责人'; +$lang->product->QM = '测试负责人'; +$lang->product->RM = '发布负责人'; +$lang->product->acl = '访问控制'; +$lang->product->whitelist = '分组白名单'; + +$lang->product->moduleStory = '按模块浏览'; +$lang->product->searchStory = '搜索'; +$lang->product->assignedToMe = '指派给我'; +$lang->product->openedByMe = '由我创建'; +$lang->product->reviewedByMe = '由我评审'; +$lang->product->closedByMe = '由我关闭'; +$lang->product->draftStory = '草稿'; +$lang->product->activeStory = '激活'; +$lang->product->changedStory = '已变更'; +$lang->product->closedStory = '已关闭'; + +$lang->product->allStory = '全部需求'; +$lang->product->allProduct = '全部产品'; + +$lang->product->statusList[''] = ''; +$lang->product->statusList['normal'] = '正常'; +$lang->product->statusList['closed'] = '结束'; + +$lang->product->aclList['open'] = '默认设置(有产品视图权限,即可访问)'; +$lang->product->aclList['private'] = '私有项目(只有项目团队成员才能访问)'; +$lang->product->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)'; + +$lang->product->storySummary = "本页共 %s 个需求,预计 %s 个工时。"; diff --git a/module/product/lang/zh-tw.php b/module/product/lang/zh-tw.php index 2d1d9500b9..965a4e2d2b 100644 --- a/module/product/lang/zh-tw.php +++ b/module/product/lang/zh-tw.php @@ -1,84 +1,84 @@ - - * @package product - * @version $Id: zh-tw.php 2588 2012-02-18 03:04:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->product->common = '產品視圖'; -$lang->product->index = "產品首頁"; -$lang->product->browse = "瀏覽產品"; -$lang->product->dynamic= "動態"; -$lang->product->view = "產品信息"; -$lang->product->edit = "編輯產品"; -$lang->product->create = "新增產品"; -$lang->product->read = "產品詳情"; -$lang->product->delete = "刪除產品"; -$lang->product->select = '--請選擇產品--'; - -$lang->product->basicInfo = '基本信息'; -$lang->product->otherInfo = '其他信息'; - -$lang->product->plans = '計劃數'; -$lang->product->releases = '發佈數'; -$lang->product->docs = '文檔數'; -$lang->product->bugs = '相關BUG'; -$lang->product->projects = '關聯項目數'; -$lang->product->cases = '用例數'; -$lang->product->bulids = 'BULID數'; -$lang->product->roadmap = '路線圖'; -$lang->product->doc = '文檔列表'; -$lang->product->project = '項目列表'; - -$lang->product->selectProduct = "請選擇產品"; -$lang->product->saveButton = " 保存 (S) "; -$lang->product->confirmDelete = " 您確定刪除該產品嗎?"; -$lang->product->ajaxGetProjects = "介面:項目列表"; -$lang->product->ajaxGetPlans = "介面:計劃列表"; - -$lang->product->errorFormat = '產品數據格式不正確'; -$lang->product->errorEmptyName = '產品名稱不能為空'; -$lang->product->errorEmptyCode = '產品代號不能為空'; -$lang->product->errorNoProduct = '還沒有創建產品!'; -$lang->product->accessDenied = '您無權訪問該產品'; - -$lang->product->id = '編號'; -$lang->product->company = '所屬公司'; -$lang->product->name = '產品名稱'; -$lang->product->code = '產品代號'; -$lang->product->order = '排序'; -$lang->product->status = '狀態'; -$lang->product->desc = '產品描述'; -$lang->product->PO = '產品負責人'; -$lang->product->QM = '測試負責人'; -$lang->product->RM = '發佈負責人'; -$lang->product->acl = '訪問控制'; -$lang->product->whitelist = '分組白名單'; - -$lang->product->moduleStory = '按模組瀏覽'; -$lang->product->searchStory = '搜索'; -$lang->product->assignedToMe = '指派給我'; -$lang->product->openedByMe = '由我創建'; -$lang->product->reviewedByMe = '由我評審'; -$lang->product->closedByMe = '由我關閉'; -$lang->product->draftStory = '草稿'; -$lang->product->activeStory = '激活'; -$lang->product->changedStory = '已變更'; -$lang->product->closedStory = '已關閉'; - -$lang->product->allStory = '全部需求'; -$lang->product->allProduct = '全部產品'; - -$lang->product->statusList[''] = ''; -$lang->product->statusList['normal'] = '正常'; -$lang->product->statusList['closed'] = '結束'; - -$lang->product->aclList['open'] = '預設設置(有產品視圖權限,即可訪問)'; -$lang->product->aclList['private'] = '私有項目(只有項目團隊成員才能訪問)'; -$lang->product->aclList['custom'] = '自定義白名單(團隊成員和白名單的成員可以訪問)'; - -$lang->product->storySummary = "本頁共 %s 個需求,預計 %s 個工時。"; + + * @package product + * @version $Id: zh-tw.php 2588 2012-02-18 03:04:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->product->common = '產品視圖'; +$lang->product->index = "產品首頁"; +$lang->product->browse = "瀏覽產品"; +$lang->product->dynamic= "動態"; +$lang->product->view = "產品信息"; +$lang->product->edit = "編輯產品"; +$lang->product->create = "新增產品"; +$lang->product->read = "產品詳情"; +$lang->product->delete = "刪除產品"; +$lang->product->select = '--請選擇產品--'; + +$lang->product->basicInfo = '基本信息'; +$lang->product->otherInfo = '其他信息'; + +$lang->product->plans = '計劃數'; +$lang->product->releases = '發佈數'; +$lang->product->docs = '文檔數'; +$lang->product->bugs = '相關BUG'; +$lang->product->projects = '關聯項目數'; +$lang->product->cases = '用例數'; +$lang->product->bulids = 'BULID數'; +$lang->product->roadmap = '路線圖'; +$lang->product->doc = '文檔列表'; +$lang->product->project = '項目列表'; + +$lang->product->selectProduct = "請選擇產品"; +$lang->product->saveButton = " 保存 (S) "; +$lang->product->confirmDelete = " 您確定刪除該產品嗎?"; +$lang->product->ajaxGetProjects = "介面:項目列表"; +$lang->product->ajaxGetPlans = "介面:計劃列表"; + +$lang->product->errorFormat = '產品數據格式不正確'; +$lang->product->errorEmptyName = '產品名稱不能為空'; +$lang->product->errorEmptyCode = '產品代號不能為空'; +$lang->product->errorNoProduct = '還沒有創建產品!'; +$lang->product->accessDenied = '您無權訪問該產品'; + +$lang->product->id = '編號'; +$lang->product->company = '所屬公司'; +$lang->product->name = '產品名稱'; +$lang->product->code = '產品代號'; +$lang->product->order = '排序'; +$lang->product->status = '狀態'; +$lang->product->desc = '產品描述'; +$lang->product->PO = '產品負責人'; +$lang->product->QM = '測試負責人'; +$lang->product->RM = '發佈負責人'; +$lang->product->acl = '訪問控制'; +$lang->product->whitelist = '分組白名單'; + +$lang->product->moduleStory = '按模組瀏覽'; +$lang->product->searchStory = '搜索'; +$lang->product->assignedToMe = '指派給我'; +$lang->product->openedByMe = '由我創建'; +$lang->product->reviewedByMe = '由我評審'; +$lang->product->closedByMe = '由我關閉'; +$lang->product->draftStory = '草稿'; +$lang->product->activeStory = '激活'; +$lang->product->changedStory = '已變更'; +$lang->product->closedStory = '已關閉'; + +$lang->product->allStory = '全部需求'; +$lang->product->allProduct = '全部產品'; + +$lang->product->statusList[''] = ''; +$lang->product->statusList['normal'] = '正常'; +$lang->product->statusList['closed'] = '結束'; + +$lang->product->aclList['open'] = '預設設置(有產品視圖權限,即可訪問)'; +$lang->product->aclList['private'] = '私有項目(只有項目團隊成員才能訪問)'; +$lang->product->aclList['custom'] = '自定義白名單(團隊成員和白名單的成員可以訪問)'; + +$lang->product->storySummary = "本頁共 %s 個需求,預計 %s 個工時。"; diff --git a/module/product/model.php b/module/product/model.php index f326fec5c6..f4e8f87501 100644 --- a/module/product/model.php +++ b/module/product/model.php @@ -1,485 +1,485 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> -checkPriv($this->getById($productID))) - { - echo(js::alert($this->lang->product->accessDenied)); - die(js::locate('back')); - } - - $currentModule = $this->app->getModuleName(); - $currentMethod = $this->app->getMethodName(); - - /* init currentModule and currentMethod for report*/ - if($currentModule == 'story') $currentModule = 'product'; - if($currentMethod == 'report') $currentMethod = 'browse'; - - $selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra); - foreach($this->lang->product->menu as $key => $menu) - { - $replace = $key == 'list' ? $selectHtml . $this->lang->arrow : $productID; - common::setMenuVars($this->lang->product->menu, $key, $replace); - } - } - - /** - * Create the select code of products. - * - * @param array $products - * @param int $productID - * @param string $currentModule - * @param string $currentMethod - * @param string $extra - * @access public - * @return string - */ - public function select($products, $productID, $currentModule, $currentMethod, $extra = '') - { - /** - * 1. if user selected by mouse, reload it. - * 2. if the user select by keyboard, save the event.keyCode, thus the switchProduct() can judge whether reload or not. - * 3. if user press enter key in the select, reload it. - * 4. if user click the go button, reload it. - * */ - $switchCode = "switchProduct($('#productID').val(), '$currentModule', '$currentMethod', '$extra');"; - $onchange = "onchange=\"$switchCode\""; - $onkeypress = "onkeypress=\"eventKeyCode=event.keyCode; if(eventKeyCode == 13) $switchCode\""; - $onclick = "onclick=\"eventKeyCode = 13; $switchCode\""; - $selectHtml = html::select('productID', $products, $productID, "tabindex=2 $onchange $onkeypress"); - $selectHtml .= html::commonButton($this->lang->go, "id='productSwitcher' tabindex=3 $onclick"); - return $selectHtml; - } - - /** - * Save the product id user last visited to session. - * - * @param int $productID - * @param array $products - * @access public - * @return int - */ - public function saveState($productID, $products) - { - if($productID > 0) $this->session->set('product', (int)$productID); - if($productID == 0 and $this->cookie->lastProduct) $this->session->set('product', (int)$this->cookie->lastProduct); - if($productID == 0 and $this->session->product == '') $this->session->set('product', key($products)); - if(!isset($products[$this->session->product])) $this->session->set('product', key($products)); - return $this->session->product; - } - - /** - * Save order - * - * @access public - * @return void - */ - public function saveOrder() - { - foreach($_POST as $productID => $order) - { - $this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($order)->where('id')->eq($productID)->exec(); - } - } - - /** - * Check privilege. - * - * @param int $product - * @access public - * @return bool - */ - public function checkPriv($product) - { - /* Is admin? */ - $account = ',' . $this->app->user->account . ','; - if(strpos($this->app->company->admins, $account) !== false) return true; - - /* Product is open, return true. */ - if($product->acl == 'open') return true; - - /* Get team members. */ - $teamMembers = $this->getTeamMemberPairs($product); - - /* Private. */ - if($product->acl == 'private') - { - return isset($teamMembers[$this->app->user->account]); - } - - /* Custom, check groups. */ - if($product->acl == 'custom') - { - if(isset($teamMembers[$this->app->user->account])) return true; - $userGroups = $this->loadModel('user')->getGroups($this->app->user->account); - $productGroups = explode(',', $product->whitelist); - foreach($userGroups as $groupID) - { - if(in_array($groupID, $productGroups)) return true; - } - return false; - } - } - - /** - * Get product by id. - * - * @param int $productID - * @access public - * @return object - */ - public function getById($productID) - { - return $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); - } - - /** - * Get products. - * - * @param string $status - * @param int $limit - * @access public - * @return array - */ - public function getList($status = 'all', $limit = 0) - { - return $this->dao->select('*')->from(TABLE_PRODUCT) - ->where('deleted')->eq(0) - ->beginIF($status = 'noclosed')->andWhere('status')->ne('closed')->fi() - ->beginIF($status != 'all' and $status != 'noclosed')->andWhere('status')->in($status)->fi() - ->beginIF($limit > 0)->limit($limit)->fi() - ->orderBy('`order` asc') - ->fetchAll('id'); - } - - /** - * Get product pairs. - * - * @param string $mode - * @return array - */ - public function getPairs($mode = '') - { - $orderBy = !empty($this->config->product->orderBy) ? $this->config->product->orderBy : 'isClosed, `order`'; - $mode .= $this->cookie->productMode; - $products = $this->dao->select('*, IF(INSTR(" closed", status) < 2, 0, 1) AS isClosed') - ->from(TABLE_PRODUCT) - ->where('deleted')->eq(0) - ->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi() - ->orderBy($orderBy) - ->fetchAll(); - $pairs = array(); - foreach($products as $product) - { - if($this->checkPriv($product)) - { - - if(strpos($mode, 'nocode') === false and $product->code) - { - $firstChar = strtoupper(substr($product->code, 0, 1)); - if(ord($firstChar) < 127) $product->name = $firstChar . ':' . $product->name; - } - - $pairs[$product->id] = $product->name; - } - } - return $pairs; - } - - /** - * Get products by project. - * - * @param int $projectID - * @access public - * @return array - */ - public function getProductsByProject($projectID) - { - return $this->dao->select('t1.product, t2.name') - ->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product = t2.id') - ->where('t1.project')->eq($projectID) - ->fetchPairs(); - } - - /** - * Get grouped products. - * - * @access public - * @return void - */ - public function getStatusGroups() - { - $products = $this->dao->select('id, name, status')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchGroup('status'); - } - - /** - * Create a product. - * - * @access public - * @return int - */ - public function create() - { - $product = fixer::input('post') - ->stripTags('name,code') - ->setIF($this->post->acl != 'custom', 'whitelist', '') - ->setDefault('status', 'normal') - ->setDefault('createdBy', $this->app->user->account) - ->setDefault('createdDate', helper::now()) - ->join('whitelist', ',') - ->get(); - $this->dao->insert(TABLE_PRODUCT) - ->data($product) - ->autoCheck() - ->batchCheck('name,code', 'notempty') - ->check('name', 'unique') - ->check('code', 'unique') - ->exec(); - return $this->dao->lastInsertID(); - } - - /** - * Update a product. - * - * @param int $productID - * @access public - * @return array - */ - public function update($productID) - { - $productID = (int)$productID; - $oldProduct = $this->getById($productID); - $product = fixer::input('post') - ->stripTags('name,code') - ->setIF($this->post->acl != 'custom', 'whitelist', '') - ->join('whitelist', ',') - ->get(); - $this->dao->update(TABLE_PRODUCT) - ->data($product) - ->autoCheck() - ->batchCheck('name,code', 'notempty') - ->check('name', 'unique', "id != $productID") - ->check('code', 'unique', "id != $productID") - ->where('id')->eq($productID) - ->exec(); - if(!dao::isError()) return common::createChanges($oldProduct, $product); - } - - /** - * Get projects of a product in pairs. - * - * @param int $productID - * @param string $param all|nodeleted - * @access public - * @return array - */ - public function getProjectPairs($productID, $param = 'all') - { - $projects = array(); - $datas = $this->dao->select('t2.id, t2.name, t2.deleted') - ->from(TABLE_PROJECTPRODUCT)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2') - ->on('t1.project = t2.id') - ->where('t1.product')->eq((int)$productID) - ->orderBy('t1.project desc') - ->fetchAll(); - - foreach($datas as $data) - { - if($param == 'nodeleted' and $data->deleted) continue; - $projects[$data->id] = $data->name; - } - $projects = array('' => '') + $projects; - return $projects; - } - - /** - * Get roadmap of a proejct - * - * @param int $productID - * @access public - * @return array - */ - public function getRoadmap($productID) - { - $plans = $this->loadModel('productplan')->getList($productID); - $releases = $this->loadModel('release')->getList($productID); - $roadmap = array(); - if(is_array($releases)) $releases = array_reverse($releases); - foreach($releases as $release) - { - $year = substr($release->date, 0, 4); - $roadmap[$year][] = $release; - } - foreach($plans as $plan) - { - if($plan->end != '0000-00-00' and strtotime($plan->end) - time() <= 0) continue; - $year = substr($plan->end, 0, 4); - $roadmap[$year][] = $plan; - } - - ksort($roadmap); - return $roadmap; - } - - /** - * Get team members of a product from projects. - * - * @param object $product - * @access public - * @return array - */ - public function getTeamMemberPairs($product) - { - $members[$product->PO] = $product->PO; - $members[$product->QM] = $product->QM; - $members[$product->RM] = $product->RM; - $members[$product->createdBy] = $product->createdBy; - - $projects = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($product->id)->fetchPairs(); - if(!$projects) return $members; - $projectTeams = $this->dao->select('account')->from(TABLE_TEAM)->where('project')->in($projects)->fetchPairs(); - return array_merge($members, $projectTeams); - } - - /** - * Get product stat by id - * - * @param int $productID - * @access public - * @return object|bool - */ - public function getStatByID($productID) - { - $product = $this->getById($productID); - if(!$this->checkPriv($product)) return false; - $stories = $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->groupBy('product, status')->fetchAll('status'); - /* Padding the stories to sure all status have records. */ - foreach(array_keys($this->lang->story->statusList) as $status) - { - $stories[$status] = isset($stories[$status]) ? $stories[$status]->count : 0; - } - - $plans = $this->dao->select('count(*) AS count')->from(TABLE_PRODUCTPLAN)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('end')->gt(helper::now())->fetch(); - $bulids = $this->dao->select('count(*) AS count')->from(TABLE_BUILD)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $cases = $this->dao->select('count(*) AS count')->from(TABLE_CASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $bugs = $this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $docs = $this->dao->select('count(*) AS count')->from(TABLE_DOC)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $releases = $this->dao->select('count(*) AS count')->from(TABLE_RELEASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $projects = $this->dao->select('count("t1.*") AS count')->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) - ->fetch(); - - $product->stories = $stories; - $product->plans = $plans ? $plans->count : 0; - $product->releases = $releases ? $releases->count : 0; - $product->bulids = $bulids ? $bulids->count : 0; - $product->cases = $cases ? $cases->count : 0; - $product->projects = $projects ? $projects->count : 0; - $product->bugs = $bugs ? $bugs->count : 0; - $product->docs = $docs ? $docs->count : 0; - - return $product; - } - - /** - * Get product stats. - * - * @access public - * @return array - */ - public function getStats() - { - $this->loadModel('report'); - $this->loadModel('story'); - - $products = $this->getList(',normal'); - $stats = array(); - - $stories = $this->dao->select('product, status, count(status) AS count') - ->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('product')->in(array_keys($products)) - ->groupBy('product, status') - ->fetchGroup('product', 'status'); - - /* Padding the stories to sure all products have records. */ - $emptyStory = array_keys($this->lang->story->statusList); - foreach(array_keys($products) as $productID) - { - if(!isset($stories[$productID])) $stories[$productID] = $emptyStory; - } - - /* Padding the stories to sure all status have records. */ - foreach($stories as $key => $story) - { - foreach(array_keys($this->lang->story->statusList) as $status) - { - $story[$status] = isset($story[$status]) ? $story[$status]->count : 0; - } - $stories[$key] = $story; - } - - $plans = $this->dao->select('product, count(*) AS count') - ->from(TABLE_PRODUCTPLAN) - ->where('deleted')->eq(0) - ->andWhere('product')->in(array_keys($products)) - ->andWhere('end')->gt(helper::now()) - ->groupBy('product') - ->fetchPairs(); - - $releases = $this->dao->select('product, count(*) AS count') - ->from(TABLE_RELEASE) - ->where('deleted')->eq(0) - ->andWhere('product')->in(array_keys($products)) - ->groupBy('product') - ->fetchPairs(); - - foreach($products as $key => $product) - { - if($this->checkPriv($product)) - { - if($product->status != 'closed') - { - $product->stories = $stories[$product->id]; - $product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0; - $product->releases= isset($releases[$product->id]) ? $releases[$product->id] : 0; - - $stats[] = $product; - } - } - else - { - unset($products[$key]); - } - } - - return $stats; - } -} + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> +checkPriv($this->getById($productID))) + { + echo(js::alert($this->lang->product->accessDenied)); + die(js::locate('back')); + } + + $currentModule = $this->app->getModuleName(); + $currentMethod = $this->app->getMethodName(); + + /* init currentModule and currentMethod for report*/ + if($currentModule == 'story') $currentModule = 'product'; + if($currentMethod == 'report') $currentMethod = 'browse'; + + $selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra); + foreach($this->lang->product->menu as $key => $menu) + { + $replace = $key == 'list' ? $selectHtml . $this->lang->arrow : $productID; + common::setMenuVars($this->lang->product->menu, $key, $replace); + } + } + + /** + * Create the select code of products. + * + * @param array $products + * @param int $productID + * @param string $currentModule + * @param string $currentMethod + * @param string $extra + * @access public + * @return string + */ + public function select($products, $productID, $currentModule, $currentMethod, $extra = '') + { + /** + * 1. if user selected by mouse, reload it. + * 2. if the user select by keyboard, save the event.keyCode, thus the switchProduct() can judge whether reload or not. + * 3. if user press enter key in the select, reload it. + * 4. if user click the go button, reload it. + * */ + $switchCode = "switchProduct($('#productID').val(), '$currentModule', '$currentMethod', '$extra');"; + $onchange = "onchange=\"$switchCode\""; + $onkeypress = "onkeypress=\"eventKeyCode=event.keyCode; if(eventKeyCode == 13) $switchCode\""; + $onclick = "onclick=\"eventKeyCode = 13; $switchCode\""; + $selectHtml = html::select('productID', $products, $productID, "tabindex=2 $onchange $onkeypress"); + $selectHtml .= html::commonButton($this->lang->go, "id='productSwitcher' tabindex=3 $onclick"); + return $selectHtml; + } + + /** + * Save the product id user last visited to session. + * + * @param int $productID + * @param array $products + * @access public + * @return int + */ + public function saveState($productID, $products) + { + if($productID > 0) $this->session->set('product', (int)$productID); + if($productID == 0 and $this->cookie->lastProduct) $this->session->set('product', (int)$this->cookie->lastProduct); + if($productID == 0 and $this->session->product == '') $this->session->set('product', key($products)); + if(!isset($products[$this->session->product])) $this->session->set('product', key($products)); + return $this->session->product; + } + + /** + * Save order + * + * @access public + * @return void + */ + public function saveOrder() + { + foreach($_POST as $productID => $order) + { + $this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($order)->where('id')->eq($productID)->exec(); + } + } + + /** + * Check privilege. + * + * @param int $product + * @access public + * @return bool + */ + public function checkPriv($product) + { + /* Is admin? */ + $account = ',' . $this->app->user->account . ','; + if(strpos($this->app->company->admins, $account) !== false) return true; + + /* Product is open, return true. */ + if($product->acl == 'open') return true; + + /* Get team members. */ + $teamMembers = $this->getTeamMemberPairs($product); + + /* Private. */ + if($product->acl == 'private') + { + return isset($teamMembers[$this->app->user->account]); + } + + /* Custom, check groups. */ + if($product->acl == 'custom') + { + if(isset($teamMembers[$this->app->user->account])) return true; + $userGroups = $this->loadModel('user')->getGroups($this->app->user->account); + $productGroups = explode(',', $product->whitelist); + foreach($userGroups as $groupID) + { + if(in_array($groupID, $productGroups)) return true; + } + return false; + } + } + + /** + * Get product by id. + * + * @param int $productID + * @access public + * @return object + */ + public function getById($productID) + { + return $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch(); + } + + /** + * Get products. + * + * @param string $status + * @param int $limit + * @access public + * @return array + */ + public function getList($status = 'all', $limit = 0) + { + return $this->dao->select('*')->from(TABLE_PRODUCT) + ->where('deleted')->eq(0) + ->beginIF($status = 'noclosed')->andWhere('status')->ne('closed')->fi() + ->beginIF($status != 'all' and $status != 'noclosed')->andWhere('status')->in($status)->fi() + ->beginIF($limit > 0)->limit($limit)->fi() + ->orderBy('`order` asc') + ->fetchAll('id'); + } + + /** + * Get product pairs. + * + * @param string $mode + * @return array + */ + public function getPairs($mode = '') + { + $orderBy = !empty($this->config->product->orderBy) ? $this->config->product->orderBy : 'isClosed, `order`'; + $mode .= $this->cookie->productMode; + $products = $this->dao->select('*, IF(INSTR(" closed", status) < 2, 0, 1) AS isClosed') + ->from(TABLE_PRODUCT) + ->where('deleted')->eq(0) + ->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('status')->ne('closed')->fi() + ->orderBy($orderBy) + ->fetchAll(); + $pairs = array(); + foreach($products as $product) + { + if($this->checkPriv($product)) + { + + if(strpos($mode, 'nocode') === false and $product->code) + { + $firstChar = strtoupper(substr($product->code, 0, 1)); + if(ord($firstChar) < 127) $product->name = $firstChar . ':' . $product->name; + } + + $pairs[$product->id] = $product->name; + } + } + return $pairs; + } + + /** + * Get products by project. + * + * @param int $projectID + * @access public + * @return array + */ + public function getProductsByProject($projectID) + { + return $this->dao->select('t1.product, t2.name') + ->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product = t2.id') + ->where('t1.project')->eq($projectID) + ->fetchPairs(); + } + + /** + * Get grouped products. + * + * @access public + * @return void + */ + public function getStatusGroups() + { + $products = $this->dao->select('id, name, status')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchGroup('status'); + } + + /** + * Create a product. + * + * @access public + * @return int + */ + public function create() + { + $product = fixer::input('post') + ->stripTags('name,code') + ->setIF($this->post->acl != 'custom', 'whitelist', '') + ->setDefault('status', 'normal') + ->setDefault('createdBy', $this->app->user->account) + ->setDefault('createdDate', helper::now()) + ->join('whitelist', ',') + ->get(); + $this->dao->insert(TABLE_PRODUCT) + ->data($product) + ->autoCheck() + ->batchCheck('name,code', 'notempty') + ->check('name', 'unique') + ->check('code', 'unique') + ->exec(); + return $this->dao->lastInsertID(); + } + + /** + * Update a product. + * + * @param int $productID + * @access public + * @return array + */ + public function update($productID) + { + $productID = (int)$productID; + $oldProduct = $this->getById($productID); + $product = fixer::input('post') + ->stripTags('name,code') + ->setIF($this->post->acl != 'custom', 'whitelist', '') + ->join('whitelist', ',') + ->get(); + $this->dao->update(TABLE_PRODUCT) + ->data($product) + ->autoCheck() + ->batchCheck('name,code', 'notempty') + ->check('name', 'unique', "id != $productID") + ->check('code', 'unique', "id != $productID") + ->where('id')->eq($productID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldProduct, $product); + } + + /** + * Get projects of a product in pairs. + * + * @param int $productID + * @param string $param all|nodeleted + * @access public + * @return array + */ + public function getProjectPairs($productID, $param = 'all') + { + $projects = array(); + $datas = $this->dao->select('t2.id, t2.name, t2.deleted') + ->from(TABLE_PROJECTPRODUCT)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2') + ->on('t1.project = t2.id') + ->where('t1.product')->eq((int)$productID) + ->orderBy('t1.project desc') + ->fetchAll(); + + foreach($datas as $data) + { + if($param == 'nodeleted' and $data->deleted) continue; + $projects[$data->id] = $data->name; + } + $projects = array('' => '') + $projects; + return $projects; + } + + /** + * Get roadmap of a proejct + * + * @param int $productID + * @access public + * @return array + */ + public function getRoadmap($productID) + { + $plans = $this->loadModel('productplan')->getList($productID); + $releases = $this->loadModel('release')->getList($productID); + $roadmap = array(); + if(is_array($releases)) $releases = array_reverse($releases); + foreach($releases as $release) + { + $year = substr($release->date, 0, 4); + $roadmap[$year][] = $release; + } + foreach($plans as $plan) + { + if($plan->end != '0000-00-00' and strtotime($plan->end) - time() <= 0) continue; + $year = substr($plan->end, 0, 4); + $roadmap[$year][] = $plan; + } + + ksort($roadmap); + return $roadmap; + } + + /** + * Get team members of a product from projects. + * + * @param object $product + * @access public + * @return array + */ + public function getTeamMemberPairs($product) + { + $members[$product->PO] = $product->PO; + $members[$product->QM] = $product->QM; + $members[$product->RM] = $product->RM; + $members[$product->createdBy] = $product->createdBy; + + $projects = $this->dao->select('project')->from(TABLE_PROJECTPRODUCT)->where('product')->eq($product->id)->fetchPairs(); + if(!$projects) return $members; + $projectTeams = $this->dao->select('account')->from(TABLE_TEAM)->where('project')->in($projects)->fetchPairs(); + return array_merge($members, $projectTeams); + } + + /** + * Get product stat by id + * + * @param int $productID + * @access public + * @return object|bool + */ + public function getStatByID($productID) + { + $product = $this->getById($productID); + if(!$this->checkPriv($product)) return false; + $stories = $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->groupBy('product, status')->fetchAll('status'); + /* Padding the stories to sure all status have records. */ + foreach(array_keys($this->lang->story->statusList) as $status) + { + $stories[$status] = isset($stories[$status]) ? $stories[$status]->count : 0; + } + + $plans = $this->dao->select('count(*) AS count')->from(TABLE_PRODUCTPLAN)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('end')->gt(helper::now())->fetch(); + $bulids = $this->dao->select('count(*) AS count')->from(TABLE_BUILD)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + $cases = $this->dao->select('count(*) AS count')->from(TABLE_CASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + $bugs = $this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + $docs = $this->dao->select('count(*) AS count')->from(TABLE_DOC)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + $releases = $this->dao->select('count(*) AS count')->from(TABLE_RELEASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + $projects = $this->dao->select('count("t1.*") AS count')->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) + ->fetch(); + + $product->stories = $stories; + $product->plans = $plans ? $plans->count : 0; + $product->releases = $releases ? $releases->count : 0; + $product->bulids = $bulids ? $bulids->count : 0; + $product->cases = $cases ? $cases->count : 0; + $product->projects = $projects ? $projects->count : 0; + $product->bugs = $bugs ? $bugs->count : 0; + $product->docs = $docs ? $docs->count : 0; + + return $product; + } + + /** + * Get product stats. + * + * @access public + * @return array + */ + public function getStats() + { + $this->loadModel('report'); + $this->loadModel('story'); + + $products = $this->getList(',normal'); + $stats = array(); + + $stories = $this->dao->select('product, status, count(status) AS count') + ->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('product')->in(array_keys($products)) + ->groupBy('product, status') + ->fetchGroup('product', 'status'); + + /* Padding the stories to sure all products have records. */ + $emptyStory = array_keys($this->lang->story->statusList); + foreach(array_keys($products) as $productID) + { + if(!isset($stories[$productID])) $stories[$productID] = $emptyStory; + } + + /* Padding the stories to sure all status have records. */ + foreach($stories as $key => $story) + { + foreach(array_keys($this->lang->story->statusList) as $status) + { + $story[$status] = isset($story[$status]) ? $story[$status]->count : 0; + } + $stories[$key] = $story; + } + + $plans = $this->dao->select('product, count(*) AS count') + ->from(TABLE_PRODUCTPLAN) + ->where('deleted')->eq(0) + ->andWhere('product')->in(array_keys($products)) + ->andWhere('end')->gt(helper::now()) + ->groupBy('product') + ->fetchPairs(); + + $releases = $this->dao->select('product, count(*) AS count') + ->from(TABLE_RELEASE) + ->where('deleted')->eq(0) + ->andWhere('product')->in(array_keys($products)) + ->groupBy('product') + ->fetchPairs(); + + foreach($products as $key => $product) + { + if($this->checkPriv($product)) + { + if($product->status != 'closed') + { + $product->stories = $stories[$product->id]; + $product->plans = isset($plans[$product->id]) ? $plans[$product->id] : 0; + $product->releases= isset($releases[$product->id]) ? $releases[$product->id] : 0; + + $stats[] = $product; + } + } + else + { + unset($products[$key]); + } + } + + return $stats; + } +} diff --git a/module/product/view/browse.html.php b/module/product/view/browse.html.php index 558d492b01..6b94c46b23 100644 --- a/module/product/view/browse.html.php +++ b/module/product/view/browse.html.php @@ -1,120 +1,120 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -
          -
          - product->moduleStory;?> - inlink('browse', "productID=$productID&browseType=assignedtome"), $lang->product->assignedToMe);?> - inlink('browse', "productID=$productID&browseType=openedByMe"), $lang->product->openedByMe);?> - inlink('browse', "productID=$productID&browseType=reviewedByMe"), $lang->product->reviewedByMe);?> - inlink('browse', "productID=$productID&browseType=closedByMe"), $lang->product->closedByMe);?> - inlink('browse', "productID=$productID&browseType=draftStory"), $lang->product->draftStory);?> - inlink('browse', "productID=$productID&browseType=activeStory"), $lang->product->activeStory);?> - inlink('browse', "productID=$productID&browseType=changedStory"), $lang->product->changedStory);?> - inlink('browse', "productID=$productID&browseType=closedStory"), $lang->product->closedStory);?> - inlink('browse', "productID=$productID&browseType=allStory"), $lang->product->allStory);?> - product->searchStory;?> -
          -
          - export, '', 'class="export"'); ?> - story->report->common); ?> - createLink('story', 'batchCreate', "productID=$productID&moduleID=$moduleID"), $lang->story->batchCreate); ?> - createLink('story', 'create', "productID=$productID&moduleID=$moduleID"), $lang->story->create); ?> -
          -
          -
          '>
          - - - - - - -
          -
          -
          - -
          - createLink('product', 'edit', "productID=$productID"), $lang->edit);?> - createLink('product', 'delete', "productID=$productID&confirm=no"), $lang->delete, 'hiddenwin');?> - createLink('tree', 'browse', "rootID=$productID&view=story"), $lang->tree->manage);?> -
          -
          -
          - - - - recTotal}&recPerPage={$pager->recPerPage}";?> - - - - - - - - - - - - - - - - $story):?> - createLink('story', 'view', "storyID=$story->id"); - $totalEstimate += $story->estimate; - $canView = common::hasPriv('story', 'view'); - ?> - - - - - - - - - - - - - - - - - - - - -
          idAB);?>priAB);?>story->title);?>story->planAB);?>story->source);?>openedByAB);?>assignedToAB);?>story->estimateAB);?>statusAB);?>story->stageAB);?>actions;?>
          id)); else printf('%03d', $story->id);?>pri;?>title);?>planTitle;?>story->sourceList[$story->source];?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> - id}"; - if(!common::printLink('testcase', 'create', "productID=$story->product&module=0&from=¶m=0&$vars", $lang->story->createCase)) echo $lang->story->createCase . ' '; - if(!($story->status != 'closed' and common::printLink('story', 'change', $vars, $lang->story->change))) echo $lang->story->change . ' '; - if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', $vars, $lang->story->review))) echo $lang->story->review . ' '; - if(!common::printLink('story', 'edit', $vars, $lang->edit)) echo $lang->edit; - ?> -
          -
          product->storySummary, count($stories), $totalEstimate);?>
          - show();?> -
          -
          - - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +
          +
          + product->moduleStory;?> + inlink('browse', "productID=$productID&browseType=assignedtome"), $lang->product->assignedToMe);?> + inlink('browse', "productID=$productID&browseType=openedByMe"), $lang->product->openedByMe);?> + inlink('browse', "productID=$productID&browseType=reviewedByMe"), $lang->product->reviewedByMe);?> + inlink('browse', "productID=$productID&browseType=closedByMe"), $lang->product->closedByMe);?> + inlink('browse', "productID=$productID&browseType=draftStory"), $lang->product->draftStory);?> + inlink('browse', "productID=$productID&browseType=activeStory"), $lang->product->activeStory);?> + inlink('browse', "productID=$productID&browseType=changedStory"), $lang->product->changedStory);?> + inlink('browse', "productID=$productID&browseType=closedStory"), $lang->product->closedStory);?> + inlink('browse', "productID=$productID&browseType=allStory"), $lang->product->allStory);?> + product->searchStory;?> +
          +
          + export, '', 'class="export"'); ?> + story->report->common); ?> + createLink('story', 'batchCreate', "productID=$productID&moduleID=$moduleID"), $lang->story->batchCreate); ?> + createLink('story', 'create', "productID=$productID&moduleID=$moduleID"), $lang->story->create); ?> +
          +
          +
          '>
          + + + + + + +
          +
          +
          + +
          + createLink('product', 'edit', "productID=$productID"), $lang->edit);?> + createLink('product', 'delete', "productID=$productID&confirm=no"), $lang->delete, 'hiddenwin');?> + createLink('tree', 'browse', "rootID=$productID&view=story"), $lang->tree->manage);?> +
          +
          +
          + + + + recTotal}&recPerPage={$pager->recPerPage}";?> + + + + + + + + + + + + + + + + $story):?> + createLink('story', 'view', "storyID=$story->id"); + $totalEstimate += $story->estimate; + $canView = common::hasPriv('story', 'view'); + ?> + + + + + + + + + + + + + + + + + + + + +
          idAB);?>priAB);?>story->title);?>story->planAB);?>story->source);?>openedByAB);?>assignedToAB);?>story->estimateAB);?>statusAB);?>story->stageAB);?>actions;?>
          id)); else printf('%03d', $story->id);?>pri;?>title);?>planTitle;?>story->sourceList[$story->source];?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> + id}"; + if(!common::printLink('testcase', 'create', "productID=$story->product&module=0&from=¶m=0&$vars", $lang->story->createCase)) echo $lang->story->createCase . ' '; + if(!($story->status != 'closed' and common::printLink('story', 'change', $vars, $lang->story->change))) echo $lang->story->change . ' '; + if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', $vars, $lang->story->review))) echo $lang->story->review . ' '; + if(!common::printLink('story', 'edit', $vars, $lang->edit)) echo $lang->edit; + ?> +
          +
          product->storySummary, count($stories), $totalEstimate);?>
          + show();?> +
          +
          + + diff --git a/module/product/view/create.html.php b/module/product/view/create.html.php index a3657994b3..86849f3d7c 100644 --- a/module/product/view/create.html.php +++ b/module/product/view/create.html.php @@ -1,53 +1,53 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          product->create;?>
          product->name;?>
          product->code;?>
          product->PO;?>app->user->account, "class='select-3'");?>
          product->QM;?>app->user->account, "class='select-3'");?>
          product->RM;?>app->user->account, "class='select-3'");?>
          product->desc;?>
          product->acl;?>product->aclList, 'open', "onclick='setWhite(this.value);'"));?>
          -
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          product->create;?>
          product->name;?>
          product->code;?>
          product->PO;?>app->user->account, "class='select-3'");?>
          product->QM;?>app->user->account, "class='select-3'");?>
          product->RM;?>app->user->account, "class='select-3'");?>
          product->desc;?>
          product->acl;?>product->aclList, 'open', "onclick='setWhite(this.value);'"));?>
          +
          + diff --git a/module/product/view/doc.html.php b/module/product/view/doc.html.php index 0c9f54e622..053396a2cd 100644 --- a/module/product/view/doc.html.php +++ b/module/product/view/doc.html.php @@ -1,54 +1,54 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - $doc):?> - createLink('doc', 'view', "docID=$doc->id"); - $canView = common::hasPriv('doc', 'view'); - ?> - - - - - - - - - - -
          id}&projectID=0&from=product", $lang->doc->create);?>
          idAB;?>doc->module;?>doc->title;?>doc->addedBy;?>doc->addedDate;?>actions;?>
          id)); else printf('%03d', $doc->id);?>module;?>title);?>addedBy];?>addedDate;?> - id}"; - if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; - if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; - ?> -
          -
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + $doc):?> + createLink('doc', 'view', "docID=$doc->id"); + $canView = common::hasPriv('doc', 'view'); + ?> + + + + + + + + + + +
          id}&projectID=0&from=product", $lang->doc->create);?>
          idAB;?>doc->module;?>doc->title;?>doc->addedBy;?>doc->addedDate;?>actions;?>
          id)); else printf('%03d', $doc->id);?>module;?>title);?>addedBy];?>addedDate;?> + id}"; + if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; + if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; + ?> +
          +
          + diff --git a/module/product/view/dynamic.html.php b/module/product/view/dynamic.html.php index ad15b8f041..a87bd6a3a3 100755 --- a/module/product/view/dynamic.html.php +++ b/module/product/view/dynamic.html.php @@ -1,56 +1,56 @@ -dynamic view file of dashboard module of ZenTaoPMS. - * - * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) - * @license LGPL (http://www.gnu.org/licenses/lgpl.html) - * @author Chunsheng Wang - * @package dashboard - * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ - * @link http://www.zentao.net - */ -?> - - -
          - ' . html::a(inlink('dynamic', "productID=$productID&type=today"), $lang->action->dynamic->today) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=yesterday"), $lang->action->dynamic->yesterday) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=thisweek"), $lang->action->dynamic->thisWeek) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=lastweek"), $lang->action->dynamic->lastWeek) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=thismonth"), $lang->action->dynamic->thisMonth) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; - echo '' . html::a(inlink('dynamic', "productID=$productID&type=all"), $lang->action->dynamic->all) . ''; - echo "" . html::select('account', $users, $account, "onchange=changeUser(this.value,$productID)") . ''; - ?> -
          - - - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - -
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          - - +dynamic view file of dashboard module of ZenTaoPMS. + * + * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) + * @license LGPL (http://www.gnu.org/licenses/lgpl.html) + * @author Chunsheng Wang + * @package dashboard + * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ + * @link http://www.zentao.net + */ +?> + + +
          + ' . html::a(inlink('dynamic', "productID=$productID&type=today"), $lang->action->dynamic->today) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=yesterday"), $lang->action->dynamic->yesterday) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=thisweek"), $lang->action->dynamic->thisWeek) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=lastweek"), $lang->action->dynamic->lastWeek) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=thismonth"), $lang->action->dynamic->thisMonth) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; + echo '' . html::a(inlink('dynamic', "productID=$productID&type=all"), $lang->action->dynamic->all) . ''; + echo "" . html::select('account', $users, $account, "onchange=changeUser(this.value,$productID)") . ''; + ?> +
          + + + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + +
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          + + diff --git a/module/product/view/edit.html.php b/module/product/view/edit.html.php index 73b107f2d8..953da1c546 100644 --- a/module/product/view/edit.html.php +++ b/module/product/view/edit.html.php @@ -1,57 +1,57 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - acl != 'custom') echo "class='hidden'";?>> - - - - -
          product->edit;?>
          product->name;?>name, "class='text-3'");?>
          product->code;?>code, "class='text-3'");?>
          product->PO;?>PO, "class='select-3'");?>
          product->QM;?>QM, "class='select-3'");?>
          product->RM;?>RM, "class='select-3'");?>
          product->status;?>product->statusList, $product->status, "class='select-3'");?>
          product->desc;?>desc), "rows='8' class='area-1'");?>
          product->acl;?>product->aclList, $product->acl, "onclick='setWhite(this.value);'"));?>
          product->whitelist;?>whitelist);?>
          -
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + acl != 'custom') echo "class='hidden'";?>> + + + + +
          product->edit;?>
          product->name;?>name, "class='text-3'");?>
          product->code;?>code, "class='text-3'");?>
          product->PO;?>PO, "class='select-3'");?>
          product->QM;?>QM, "class='select-3'");?>
          product->RM;?>RM, "class='select-3'");?>
          product->status;?>product->statusList, $product->status, "class='select-3'");?>
          product->desc;?>desc), "rows='8' class='area-1'");?>
          product->acl;?>product->aclList, $product->acl, "onclick='setWhite(this.value);'"));?>
          product->whitelist;?>whitelist);?>
          +
          + diff --git a/module/product/view/index.html.php b/module/product/view/index.html.php index 8550e86617..e6ef493437 100644 --- a/module/product/view/index.html.php +++ b/module/product/view/index.html.php @@ -1,54 +1,54 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - -
          - - - - - - -
          my->home->products;?>
          - createLink('product', 'create'); - printf($lang->my->home->noProductsTip, $productLink); - ?> -
          - - - - - - - - - - - - - - - - - - - - - - -
          product->name;?>story->statusList['active'] . $lang->story->common;?>story->statusList['changed'] . $lang->story->common;?>story->statusList['draft'] . $lang->story->common;?>story->statusList['closed'] . $lang->story->common;?>product->plans;?>product->releases;?>
          createLink('product', 'view', 'product=' . $product->id), $product->name);?>stories['active']?>stories['changed']?>stories['draft']?>stories['closed']?>plans?>releases?>
          -
          - - - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + +
          + + + + + + +
          my->home->products;?>
          + createLink('product', 'create'); + printf($lang->my->home->noProductsTip, $productLink); + ?> +
          + + + + + + + + + + + + + + + + + + + + + + +
          product->name;?>story->statusList['active'] . $lang->story->common;?>story->statusList['changed'] . $lang->story->common;?>story->statusList['draft'] . $lang->story->common;?>story->statusList['closed'] . $lang->story->common;?>product->plans;?>product->releases;?>
          createLink('product', 'view', 'product=' . $product->id), $product->name);?>stories['active']?>stories['changed']?>stories['draft']?>stories['closed']?>plans?>releases?>
          +
          + + + diff --git a/module/product/view/project.html.php b/module/product/view/project.html.php index 006d5088f1..f2041b394b 100644 --- a/module/product/view/project.html.php +++ b/module/product/view/project.html.php @@ -1,44 +1,44 @@ - - * @package ZenTaoPMS - * @version $Id: index.html.php 2343 2011-11-21 05:24:56Z wwccss $ - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          project->name;?>project->code;?>project->end;?>project->status;?>project->totalEstimate;?>project->totalConsumed;?>project->totalLeft;?>project->progess;?>project->burn;?>
          createLink('project', 'task', 'project=' . $project->id), $project->name, '_parent');?>code;?>end;?>project->statusList[$project->status];?>hours->totalEstimate;?>hours->totalConsumed;?>hours->totalLeft;?> - hours->progress;?> height='13' text-align: /> - hours->progress;?>% - burns);?>'>
          - + + * @package ZenTaoPMS + * @version $Id: index.html.php 2343 2011-11-21 05:24:56Z wwccss $ + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          project->name;?>project->code;?>project->end;?>project->status;?>project->totalEstimate;?>project->totalConsumed;?>project->totalLeft;?>project->progess;?>project->burn;?>
          createLink('project', 'task', 'project=' . $project->id), $project->name, '_parent');?>code;?>end;?>project->statusList[$project->status];?>hours->totalEstimate;?>hours->totalConsumed;?>hours->totalLeft;?> + hours->progress;?> height='13' text-align: /> + hours->progress;?>% + burns);?>'>
          + diff --git a/module/product/view/roadmap.html.php b/module/product/view/roadmap.html.php index cffecf69fc..3503464a9a 100644 --- a/module/product/view/roadmap.html.php +++ b/module/product/view/roadmap.html.php @@ -1,49 +1,49 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - '; - foreach($years as $year) - { - $year = $year == '0000' ? $lang->future : $year . $lang->year; - echo ""; - } - echo ''; - echo ''; - foreach($years as $year) - { - echo ''; - } - echo ''; - ?> -
          product->roadmap;?>
          $year
          '; - foreach($roadmaps[$year] as $key => $roadmap) - { - if(isset($roadmap->build)) - { - echo "
          "; - echo "

          " . html::a($this->createLink('release', 'view', "releaseID=$roadmap->id"), $roadmap->name, '_blank') . '

          ' . $roadmap->date; - } - else - { - echo "
          "; - echo "

          " . html::a($this->createLink('productplan', 'view', "planID=$roadmap->id"), $roadmap->title, '_blank') . '

          ' . $roadmap->begin . ' ~ ' . $roadmap->end; - } - echo "
          "; - if(isset($roadmaps[$year][$key + 1])) echo "{$lang->downArrow}"; - } - echo '
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + '; + foreach($years as $year) + { + $year = $year == '0000' ? $lang->future : $year . $lang->year; + echo ""; + } + echo ''; + echo ''; + foreach($years as $year) + { + echo ''; + } + echo ''; + ?> +
          product->roadmap;?>
          $year
          '; + foreach($roadmaps[$year] as $key => $roadmap) + { + if(isset($roadmap->build)) + { + echo "
          "; + echo "

          " . html::a($this->createLink('release', 'view', "releaseID=$roadmap->id"), $roadmap->name, '_blank') . '

          ' . $roadmap->date; + } + else + { + echo "
          "; + echo "

          " . html::a($this->createLink('productplan', 'view', "planID=$roadmap->id"), $roadmap->title, '_blank') . '

          ' . $roadmap->begin . ' ~ ' . $roadmap->end; + } + echo "
          "; + if(isset($roadmaps[$year][$key + 1])) echo "{$lang->downArrow}"; + } + echo '
          + diff --git a/module/product/view/view.html.php b/module/product/view/view.html.php index 9599dcf04d..a3cca74c6f 100644 --- a/module/product/view/view.html.php +++ b/module/product/view/view.html.php @@ -1,151 +1,151 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - -
          - product->view;?> -
          - session->productList ? $this->session->productList : inlink('browse', "productID=$product->id"); - if(!$product->deleted) - { - common::printLink('product', 'edit', "productID=$product->id", $lang->edit); - common::printLink('product', 'delete', "productID=$product->id", $lang->delete, 'hiddenwin'); - } - ?> -
          -
          -
          - product->desc;?> -
          desc;?>
          -
          - -
          - session->productList ? $this->session->productList : inlink('browse', "productID=$product->id"); - if(!$product->deleted) - { - common::printLink('product', 'edit', "productID=$product->id", $lang->edit); - common::printLink('product', 'delete', "productID=$product->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          -
          -
          - product->basicInfo?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          product->name;?>deleted) echo "class='deleted'";?>>name;?>
          product->code;?>code;?>
          product->PO;?>PO];?>
          product->QM;?>QM];?>
          product->RM;?>RM];?>
          product->status;?>product->statusList[$product->status];?>
          product->acl;?>product->aclList[$product->acl];?>
          product->whitelist;?> - whitelist); - foreach($whitelist as $groupID) if(isset($groups[$groupID])) echo $groups[$groupID] . ' '; - ?> -
          story->openedBy?>createdBy;?>
          story->openedDate?>createdDate;?>
          -
          -
          - product->otherInfo?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          story->statusList['active'] . $lang->story->common;?>stories['active']?>
          story->statusList['changed'] . $lang->story->common;?>stories['changed']?>
          story->statusList['draft'] . $lang->story->common;?>stories['draft']?>
          story->statusList['closed'] . $lang->story->common;?>stories['closed']?>
          product->plans?>plans?>
          product->projects?>projects?>
          product->bugs?>bugs?>
          product->docs?>docs?>
          product->cases?>cases?>
          product->bulids?>bulids?>
          product->releases?>releases?>
          -
          -
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + +
          + product->view;?> +
          + session->productList ? $this->session->productList : inlink('browse', "productID=$product->id"); + if(!$product->deleted) + { + common::printLink('product', 'edit', "productID=$product->id", $lang->edit); + common::printLink('product', 'delete', "productID=$product->id", $lang->delete, 'hiddenwin'); + } + ?> +
          +
          +
          + product->desc;?> +
          desc;?>
          +
          + +
          + session->productList ? $this->session->productList : inlink('browse', "productID=$product->id"); + if(!$product->deleted) + { + common::printLink('product', 'edit', "productID=$product->id", $lang->edit); + common::printLink('product', 'delete', "productID=$product->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          +
          +
          + product->basicInfo?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          product->name;?>deleted) echo "class='deleted'";?>>name;?>
          product->code;?>code;?>
          product->PO;?>PO];?>
          product->QM;?>QM];?>
          product->RM;?>RM];?>
          product->status;?>product->statusList[$product->status];?>
          product->acl;?>product->aclList[$product->acl];?>
          product->whitelist;?> + whitelist); + foreach($whitelist as $groupID) if(isset($groups[$groupID])) echo $groups[$groupID] . ' '; + ?> +
          story->openedBy?>createdBy;?>
          story->openedDate?>createdDate;?>
          +
          +
          + product->otherInfo?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          story->statusList['active'] . $lang->story->common;?>stories['active']?>
          story->statusList['changed'] . $lang->story->common;?>stories['changed']?>
          story->statusList['draft'] . $lang->story->common;?>stories['draft']?>
          story->statusList['closed'] . $lang->story->common;?>stories['closed']?>
          product->plans?>plans?>
          product->projects?>projects?>
          product->bugs?>bugs?>
          product->docs?>docs?>
          product->cases?>cases?>
          product->bulids?>bulids?>
          product->releases?>releases?>
          +
          +
          + diff --git a/module/productplan/control.php b/module/productplan/control.php index 9fd67397db..65016c3b8a 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -1,192 +1,192 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -class productplan extends control -{ - /** - * Common actions - * - * @param int $productID - * @access public - * @return void - */ - public function commonAction($productID) - { - $this->loadModel('product'); - $this->view->product = $this->product->getById($productID); - $this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name); - $this->product->setMenu($this->product->getPairs(), $productID); - } - - /** - * Create a plan. - * - * @param int $product - * @access public - * @return void - */ - public function create($product = '') - { - if(!empty($_POST)) - { - $planID = $this->productplan->create(); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('productplan', $planID, 'opened'); - die(js::locate($this->createLink('productplan', 'browse', "product=$product"), 'parent')); - } - - $this->commonAction($product); - - $this->view->header->title = $this->lang->productplan->create; - $this->display(); - } - - /** - * Edit a plan. - * - * @param int $planID - * @access public - * @return void - */ - public function edit($planID) - { - if(!empty($_POST)) - { - $changes = $this->productplan->update($planID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('productplan', $planID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "planID=$planID"), 'parent')); - } - - $plan = $this->productplan->getByID($planID); - $this->commonAction($plan->product); - $this->view->header->title = $this->lang->productplan->edit; - $this->view->position[] = $this->lang->productplan->edit; - $this->view->plan = $plan; - $this->display(); - } - - /** - * Delete a plan. - * - * @param int $planID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($planID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->productplan->confirmDelete, $this->createLink('productPlan', 'delete', "planID=$planID&confirm=yes"))); - } - else - { - $plan = $this->productplan->getById($planID); - $this->productplan->delete(TABLE_PRODUCTPLAN, $planID); - die(js::locate(inlink('browse', "productID=$plan->product"), 'parent')); - } - } - - /** - * Browse plans. - * - * @param int $product - * @access public - * @return void - */ - public function browse($product = 0) - { - $this->session->set('productPlanList', $this->app->getURI(true)); - $this->commonAction($product); - $this->view->header->title = $this->lang->productplan->browse; - $this->view->position[] = $this->lang->productplan->browse; - $this->view->plans = $this->productplan->getList($product); - $this->display(); - } - - /** - * View plan. - * - * @param int $planID - * @access public - * @return void - */ - public function view($planID = 0) - { - $this->session->set('storyList', $this->app->getURI(true)); - - $plan = $this->productplan->getByID($planID); - if(!$plan) die(js::error($this->lang->notFound) . js::locate('back')); - - $this->commonAction($plan->product); - - $this->view->header->title = $this->lang->productplan->view; - $this->view->position[] = $this->lang->productplan->view; - $this->view->planStories= $this->loadModel('story')->getPlanStories($planID); - $this->view->products = $this->product->getPairs(); - $this->view->plan = $plan; - $this->view->actions = $this->loadModel('action')->getList('productplan', $planID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Link stories. - * - * @param int $planID - * @access public - * @return void - */ - public function linkStory($planID = 0) - { - $this->session->set('storyList', $this->app->getURI(true)); - - if(!empty($_POST)) $this->productplan->linkStory($planID); - - $plan = $this->productplan->getByID($planID); - $this->commonAction($plan->product); - $this->view->header->title = $this->lang->productplan->linkStory; - $this->view->position[] = $this->lang->productplan->linkStory; - $this->view->allStories = $this->loadModel('story')->getProductStories($this->view->product->id, $moduleID = '0', $status = 'draft,active,changed'); - $this->view->planStories= $this->story->getPlanStories($planID); - $this->view->products = $this->product->getPairs(); - $this->view->plan = $plan; - $this->view->plans = $this->dao->select('id, end')->from(TABLE_PRODUCTPLAN)->fetchPairs(); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Unlink story - * - * @param int $storyID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function unlinkStory($storyID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->productplan->confirmUnlinkStory, $this->createLink('productplan', 'unlinkstory', "storyID=$storyID&confirm=yes"))); - } - else - { - $this->productplan->unlinkStory($storyID); - die(js::reload('parent')); - } - } -} + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +class productplan extends control +{ + /** + * Common actions + * + * @param int $productID + * @access public + * @return void + */ + public function commonAction($productID) + { + $this->loadModel('product'); + $this->view->product = $this->product->getById($productID); + $this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name); + $this->product->setMenu($this->product->getPairs(), $productID); + } + + /** + * Create a plan. + * + * @param int $product + * @access public + * @return void + */ + public function create($product = '') + { + if(!empty($_POST)) + { + $planID = $this->productplan->create(); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('productplan', $planID, 'opened'); + die(js::locate($this->createLink('productplan', 'browse', "product=$product"), 'parent')); + } + + $this->commonAction($product); + + $this->view->header->title = $this->lang->productplan->create; + $this->display(); + } + + /** + * Edit a plan. + * + * @param int $planID + * @access public + * @return void + */ + public function edit($planID) + { + if(!empty($_POST)) + { + $changes = $this->productplan->update($planID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('productplan', $planID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "planID=$planID"), 'parent')); + } + + $plan = $this->productplan->getByID($planID); + $this->commonAction($plan->product); + $this->view->header->title = $this->lang->productplan->edit; + $this->view->position[] = $this->lang->productplan->edit; + $this->view->plan = $plan; + $this->display(); + } + + /** + * Delete a plan. + * + * @param int $planID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($planID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->productplan->confirmDelete, $this->createLink('productPlan', 'delete', "planID=$planID&confirm=yes"))); + } + else + { + $plan = $this->productplan->getById($planID); + $this->productplan->delete(TABLE_PRODUCTPLAN, $planID); + die(js::locate(inlink('browse', "productID=$plan->product"), 'parent')); + } + } + + /** + * Browse plans. + * + * @param int $product + * @access public + * @return void + */ + public function browse($product = 0) + { + $this->session->set('productPlanList', $this->app->getURI(true)); + $this->commonAction($product); + $this->view->header->title = $this->lang->productplan->browse; + $this->view->position[] = $this->lang->productplan->browse; + $this->view->plans = $this->productplan->getList($product); + $this->display(); + } + + /** + * View plan. + * + * @param int $planID + * @access public + * @return void + */ + public function view($planID = 0) + { + $this->session->set('storyList', $this->app->getURI(true)); + + $plan = $this->productplan->getByID($planID); + if(!$plan) die(js::error($this->lang->notFound) . js::locate('back')); + + $this->commonAction($plan->product); + + $this->view->header->title = $this->lang->productplan->view; + $this->view->position[] = $this->lang->productplan->view; + $this->view->planStories= $this->loadModel('story')->getPlanStories($planID); + $this->view->products = $this->product->getPairs(); + $this->view->plan = $plan; + $this->view->actions = $this->loadModel('action')->getList('productplan', $planID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Link stories. + * + * @param int $planID + * @access public + * @return void + */ + public function linkStory($planID = 0) + { + $this->session->set('storyList', $this->app->getURI(true)); + + if(!empty($_POST)) $this->productplan->linkStory($planID); + + $plan = $this->productplan->getByID($planID); + $this->commonAction($plan->product); + $this->view->header->title = $this->lang->productplan->linkStory; + $this->view->position[] = $this->lang->productplan->linkStory; + $this->view->allStories = $this->loadModel('story')->getProductStories($this->view->product->id, $moduleID = '0', $status = 'draft,active,changed'); + $this->view->planStories= $this->story->getPlanStories($planID); + $this->view->products = $this->product->getPairs(); + $this->view->plan = $plan; + $this->view->plans = $this->dao->select('id, end')->from(TABLE_PRODUCTPLAN)->fetchPairs(); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Unlink story + * + * @param int $storyID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function unlinkStory($storyID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->productplan->confirmUnlinkStory, $this->createLink('productplan', 'unlinkstory', "storyID=$storyID&confirm=yes"))); + } + else + { + $this->productplan->unlinkStory($storyID); + die(js::reload('parent')); + } + } +} diff --git a/module/productplan/lang/en.php b/module/productplan/lang/en.php index 31bdb4f88b..d6c63f996e 100644 --- a/module/productplan/lang/en.php +++ b/module/productplan/lang/en.php @@ -1,34 +1,34 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->productplan->common = 'Plan'; -$lang->productplan->browse = "Browse"; -$lang->productplan->index = "Index"; -$lang->productplan->create = "Create"; -$lang->productplan->edit = "Edit"; -$lang->productplan->delete = "Delete"; -$lang->productplan->view = "Info"; -$lang->productplan->linkStory = "Link story"; -$lang->productplan->unlinkStory = "Remove story"; -$lang->productplan->linkedStories = 'Stories linked'; -$lang->productplan->unlinkedStories = 'Stories unlinked'; - -$lang->productplan->confirmDelete = "Are you sure to delete this plan?"; -$lang->productplan->confirmUnlinkStory = "Are you sure to remove this story?"; - -$lang->productplan->id = 'ID'; -$lang->productplan->product = 'Product'; -$lang->productplan->title = 'Title'; -$lang->productplan->desc = 'Desc'; -$lang->productplan->begin = 'Begin'; -$lang->productplan->end = 'End'; - -$lang->productplan->storySummary = "Total 『%s』stories, estimate『%s』hours."; + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->productplan->common = 'Plan'; +$lang->productplan->browse = "Browse"; +$lang->productplan->index = "Index"; +$lang->productplan->create = "Create"; +$lang->productplan->edit = "Edit"; +$lang->productplan->delete = "Delete"; +$lang->productplan->view = "Info"; +$lang->productplan->linkStory = "Link story"; +$lang->productplan->unlinkStory = "Remove story"; +$lang->productplan->linkedStories = 'Stories linked'; +$lang->productplan->unlinkedStories = 'Stories unlinked'; + +$lang->productplan->confirmDelete = "Are you sure to delete this plan?"; +$lang->productplan->confirmUnlinkStory = "Are you sure to remove this story?"; + +$lang->productplan->id = 'ID'; +$lang->productplan->product = 'Product'; +$lang->productplan->title = 'Title'; +$lang->productplan->desc = 'Desc'; +$lang->productplan->begin = 'Begin'; +$lang->productplan->end = 'End'; + +$lang->productplan->storySummary = "Total 『%s』stories, estimate『%s』hours."; diff --git a/module/productplan/lang/zh-cn.php b/module/productplan/lang/zh-cn.php index d85a9a44f4..569aa41a0b 100644 --- a/module/productplan/lang/zh-cn.php +++ b/module/productplan/lang/zh-cn.php @@ -1,32 +1,32 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->productplan->common = '产品计划'; -$lang->productplan->browse = "浏览计划"; -$lang->productplan->index = "计划列表"; -$lang->productplan->create = "创建计划"; -$lang->productplan->edit = "编辑计划"; -$lang->productplan->delete = "删除计划"; -$lang->productplan->view = "计划详情"; -$lang->productplan->linkStory = "关联需求"; -$lang->productplan->unlinkStory = "移除需求"; -$lang->productplan->linkedStories = '已关联需求列表'; -$lang->productplan->unlinkedStories = '未关联需求列表'; - -$lang->productplan->confirmDelete = "您确认删除该计划吗?"; -$lang->productplan->confirmUnlinkStory = "您确认移除该需求吗?"; - -$lang->productplan->id = '编号'; -$lang->productplan->product = '产品'; -$lang->productplan->title = '名称'; -$lang->productplan->desc = '描述'; -$lang->productplan->begin = '开始日期'; -$lang->productplan->end = '结束日期'; + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->productplan->common = '产品计划'; +$lang->productplan->browse = "浏览计划"; +$lang->productplan->index = "计划列表"; +$lang->productplan->create = "创建计划"; +$lang->productplan->edit = "编辑计划"; +$lang->productplan->delete = "删除计划"; +$lang->productplan->view = "计划详情"; +$lang->productplan->linkStory = "关联需求"; +$lang->productplan->unlinkStory = "移除需求"; +$lang->productplan->linkedStories = '已关联需求列表'; +$lang->productplan->unlinkedStories = '未关联需求列表'; + +$lang->productplan->confirmDelete = "您确认删除该计划吗?"; +$lang->productplan->confirmUnlinkStory = "您确认移除该需求吗?"; + +$lang->productplan->id = '编号'; +$lang->productplan->product = '产品'; +$lang->productplan->title = '名称'; +$lang->productplan->desc = '描述'; +$lang->productplan->begin = '开始日期'; +$lang->productplan->end = '结束日期'; diff --git a/module/productplan/lang/zh-tw.php b/module/productplan/lang/zh-tw.php index 745c8b4215..83ef607bd5 100644 --- a/module/productplan/lang/zh-tw.php +++ b/module/productplan/lang/zh-tw.php @@ -1,32 +1,32 @@ - - * @package productplan - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->productplan->common = '產品計劃'; -$lang->productplan->browse = "瀏覽計劃"; -$lang->productplan->index = "計劃列表"; -$lang->productplan->create = "創建計劃"; -$lang->productplan->edit = "編輯計劃"; -$lang->productplan->delete = "刪除計劃"; -$lang->productplan->view = "計劃詳情"; -$lang->productplan->linkStory = "關聯需求"; -$lang->productplan->unlinkStory = "移除需求"; -$lang->productplan->linkedStories = '已關聯需求列表'; -$lang->productplan->unlinkedStories = '未關聯需求列表'; - -$lang->productplan->confirmDelete = "您確認刪除該計劃嗎?"; -$lang->productplan->confirmUnlinkStory = "您確認移除該需求嗎?"; - -$lang->productplan->id = '編號'; -$lang->productplan->product = '產品'; -$lang->productplan->title = '名稱'; -$lang->productplan->desc = '描述'; -$lang->productplan->begin = '開始日期'; -$lang->productplan->end = '結束日期'; + + * @package productplan + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->productplan->common = '產品計劃'; +$lang->productplan->browse = "瀏覽計劃"; +$lang->productplan->index = "計劃列表"; +$lang->productplan->create = "創建計劃"; +$lang->productplan->edit = "編輯計劃"; +$lang->productplan->delete = "刪除計劃"; +$lang->productplan->view = "計劃詳情"; +$lang->productplan->linkStory = "關聯需求"; +$lang->productplan->unlinkStory = "移除需求"; +$lang->productplan->linkedStories = '已關聯需求列表'; +$lang->productplan->unlinkedStories = '未關聯需求列表'; + +$lang->productplan->confirmDelete = "您確認刪除該計劃嗎?"; +$lang->productplan->confirmUnlinkStory = "您確認移除該需求嗎?"; + +$lang->productplan->id = '編號'; +$lang->productplan->product = '產品'; +$lang->productplan->title = '名稱'; +$lang->productplan->desc = '描述'; +$lang->productplan->begin = '開始日期'; +$lang->productplan->end = '結束日期'; diff --git a/module/productplan/model.php b/module/productplan/model.php index 02b933ede8..6e01b31d69 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -1,125 +1,125 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->findByID((int)$planID)->from(TABLE_PRODUCTPLAN)->fetch(); - $plan->desc = $this->loadModel('file')->setImgSize($plan->desc); - return $plan; - } - - /** - * Get list - * - * @param int $product - * @access public - * @return object - */ - public function getList($product = 0) - { - return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('product')->eq($product) - ->andWhere('deleted')->eq(0) - ->orderBy('begin')->fetchAll(); - } - - /** - * Get plan pairs. - * - * @param int $product - * @param string $expired - * @access public - * @return array - */ - public function getPairs($product = 0, $expired = '') - { - $date = date('Y-m-d'); - return array('' => '') + $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN) - ->where('product')->eq((int)$product) - ->andWhere('deleted')->eq(0) - ->beginIF($expired = 'unexpired') - ->andWhere('end')->gt($date) - ->fi() - ->orderBy('begin')->fetchPairs(); - } - - /** - * Create a plan. - * - * @access public - * @return int - */ - public function create() - { - $plan = fixer::input('post')->stripTags('title')->get(); - $this->dao->insert(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->batchCheck($this->config->productplan->create->requiredFields, 'notempty')->exec(); - if(!dao::isError()) return $this->dao->lastInsertID(); - } - - /** - * Update a plan - * - * @param int $planID - * @access public - * @return array - */ - public function update($planID) - { - $oldPlan = $this->getById($planID); - $plan = fixer::input('post')->stripTags('title')->get(); - $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->batchCheck($this->config->productplan->edit->requiredFields, 'notempty')->where('id')->eq((int)$planID)->exec(); - if(!dao::isError()) return common::createChanges($oldPlan, $plan); - } - - /** - * Link stories. - * - * @param int $planID - * @access public - * @return void - */ - public function linkStory($planID) - { - $this->loadModel('story'); - $this->loadModel('action'); - foreach($this->post->stories as $storyID) - { - $this->dao->update(TABLE_STORY)->set('plan')->eq((int)$planID)->where('id')->eq((int)$storyID)->exec(); - $this->action->create('story', $storyID, 'linked2plan', '', $planID); - $this->story->setStage($storyID); - } - } - - /** - * Unlink story - * - * @param int $storyID - * @access public - * @return void - */ - public function unlinkStory($storyID) - { - $planID = $this->dao->findByID($storyID)->from(TABLE_STORY)->fields('plan')->fetch('plan'); - $this->dao->update(TABLE_STORY)->set('plan')->eq(0)->where('id')->eq((int)$storyID)->exec(); - $this->loadModel('story')->setStage($storyID); - $this->loadModel('action')->create('story', $storyID, 'unlinkedfromplan', '', $planID); - } -} + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->findByID((int)$planID)->from(TABLE_PRODUCTPLAN)->fetch(); + $plan->desc = $this->loadModel('file')->setImgSize($plan->desc); + return $plan; + } + + /** + * Get list + * + * @param int $product + * @access public + * @return object + */ + public function getList($product = 0) + { + return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('product')->eq($product) + ->andWhere('deleted')->eq(0) + ->orderBy('begin')->fetchAll(); + } + + /** + * Get plan pairs. + * + * @param int $product + * @param string $expired + * @access public + * @return array + */ + public function getPairs($product = 0, $expired = '') + { + $date = date('Y-m-d'); + return array('' => '') + $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN) + ->where('product')->eq((int)$product) + ->andWhere('deleted')->eq(0) + ->beginIF($expired = 'unexpired') + ->andWhere('end')->gt($date) + ->fi() + ->orderBy('begin')->fetchPairs(); + } + + /** + * Create a plan. + * + * @access public + * @return int + */ + public function create() + { + $plan = fixer::input('post')->stripTags('title')->get(); + $this->dao->insert(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->batchCheck($this->config->productplan->create->requiredFields, 'notempty')->exec(); + if(!dao::isError()) return $this->dao->lastInsertID(); + } + + /** + * Update a plan + * + * @param int $planID + * @access public + * @return array + */ + public function update($planID) + { + $oldPlan = $this->getById($planID); + $plan = fixer::input('post')->stripTags('title')->get(); + $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->autoCheck()->batchCheck($this->config->productplan->edit->requiredFields, 'notempty')->where('id')->eq((int)$planID)->exec(); + if(!dao::isError()) return common::createChanges($oldPlan, $plan); + } + + /** + * Link stories. + * + * @param int $planID + * @access public + * @return void + */ + public function linkStory($planID) + { + $this->loadModel('story'); + $this->loadModel('action'); + foreach($this->post->stories as $storyID) + { + $this->dao->update(TABLE_STORY)->set('plan')->eq((int)$planID)->where('id')->eq((int)$storyID)->exec(); + $this->action->create('story', $storyID, 'linked2plan', '', $planID); + $this->story->setStage($storyID); + } + } + + /** + * Unlink story + * + * @param int $storyID + * @access public + * @return void + */ + public function unlinkStory($storyID) + { + $planID = $this->dao->findByID($storyID)->from(TABLE_STORY)->fields('plan')->fetch('plan'); + $this->dao->update(TABLE_STORY)->set('plan')->eq(0)->where('id')->eq((int)$storyID)->exec(); + $this->loadModel('story')->setStage($storyID); + $this->loadModel('action')->create('story', $storyID, 'unlinkedfromplan', '', $planID); + } +} diff --git a/module/productplan/view/browse.html.php b/module/productplan/view/browse.html.php index f2f31251e3..6f2639e352 100644 --- a/module/productplan/view/browse.html.php +++ b/module/productplan/view/browse.html.php @@ -1,49 +1,49 @@ - - * @package plan - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          productplan->browse;?>
          -
          id", $lang->productplan->create);?>
          -
          idAB;?>productplan->begin;?>productplan->end;?>productplan->title;?>productplan->desc;?>actions;?>
          id"), $plan->id);?>begin;?>end;?>id"), $plan->title);?>desc;?> - id", $lang->edit); - common::printLink('productplan', 'linkstory', "planID=$plan->id", $lang->productplan->linkStory); - common::printLink('productplan', 'delete', "planID=$plan->id", $lang->delete, 'hiddenwin'); - ?> -
          - + + * @package plan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          productplan->browse;?>
          +
          id", $lang->productplan->create);?>
          +
          idAB;?>productplan->begin;?>productplan->end;?>productplan->title;?>productplan->desc;?>actions;?>
          id"), $plan->id);?>begin;?>end;?>id"), $plan->title);?>desc;?> + id", $lang->edit); + common::printLink('productplan', 'linkstory', "planID=$plan->id", $lang->productplan->linkStory); + common::printLink('productplan', 'delete', "planID=$plan->id", $lang->delete, 'hiddenwin'); + ?> +
          + diff --git a/module/productplan/view/create.html.php b/module/productplan/view/create.html.php index d245c593c6..5bb9aa21fa 100644 --- a/module/productplan/view/create.html.php +++ b/module/productplan/view/create.html.php @@ -1,50 +1,50 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - -
          productplan->create;?>
          productplan->product;?>name;?>
          productplan->title;?>
          productplan->begin;?>
          productplan->end;?>
          productplan->desc;?>
          - id); - ?> -
          -
          - + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + +
          productplan->create;?>
          productplan->product;?>name;?>
          productplan->title;?>
          productplan->begin;?>
          productplan->end;?>
          productplan->desc;?>
          + id); + ?> +
          +
          + diff --git a/module/productplan/view/edit.html.php b/module/productplan/view/edit.html.php index 1da443f010..92ce03e83e 100644 --- a/module/productplan/view/edit.html.php +++ b/module/productplan/view/edit.html.php @@ -1,50 +1,50 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - -
          productplan->edit;?>
          productplan->product;?>name;?>
          productplan->title;?>title, 'class="text-3"');?>
          productplan->begin;?>begin, 'class="text-3 date"');?>
          productplan->end;?>end, 'class="text-3 date"');?>
          productplan->desc;?>desc), "rows='10' class='area-1'");?>
          - id); - ?> -
          -
          - + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + +
          productplan->edit;?>
          productplan->product;?>name;?>
          productplan->title;?>title, 'class="text-3"');?>
          productplan->begin;?>begin, 'class="text-3 date"');?>
          productplan->end;?>end, 'class="text-3 date"');?>
          productplan->desc;?>desc), "rows='10' class='area-1'");?>
          + id); + ?> +
          +
          + diff --git a/module/productplan/view/linkstory.html.php b/module/productplan/view/linkstory.html.php index e523dc7ba8..e1a995dfed 100644 --- a/module/productplan/view/linkstory.html.php +++ b/module/productplan/view/linkstory.html.php @@ -1,89 +1,89 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - id])) continue; - if($story->plan and helper::diffDate($plans[$story->plan], helper::today()) > 0) continue; - ?> - - - - - - - - - - - - - - - - - - -
          title .$lang->colon . $lang->productplan->unlinkedStories;?>
          idAB;?>priAB;?>story->plan;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>link;?>
          createLink('story', 'view', "storyID=$story->id"), $story->id);?>pri;?>planTitle;?>createLink('story', 'view', "storyID=$story->id"), $story->title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>
          story->linkStory);?>
          -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          title .$lang->colon . $lang->productplan->linkedStories;?>
          idAB;?>priAB;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions?>
          createLink('story', 'view', "storyID=$story->id"), $story->id);?>pri;?>createLink('story', 'view', "storyID=$story->id"), $story->title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>id", $lang->productplan->unlinkStory, 'hiddenwin');?>
          - + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + id])) continue; + if($story->plan and helper::diffDate($plans[$story->plan], helper::today()) > 0) continue; + ?> + + + + + + + + + + + + + + + + + + +
          title .$lang->colon . $lang->productplan->unlinkedStories;?>
          idAB;?>priAB;?>story->plan;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>link;?>
          createLink('story', 'view', "storyID=$story->id"), $story->id);?>pri;?>planTitle;?>createLink('story', 'view', "storyID=$story->id"), $story->title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>
          story->linkStory);?>
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          title .$lang->colon . $lang->productplan->linkedStories;?>
          idAB;?>priAB;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions?>
          createLink('story', 'view', "storyID=$story->id"), $story->id);?>pri;?>createLink('story', 'view', "storyID=$story->id"), $story->title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>id", $lang->productplan->unlinkStory, 'hiddenwin');?>
          + diff --git a/module/productplan/view/view.html.php b/module/productplan/view/view.html.php index a8985279a7..b1d2afc738 100644 --- a/module/productplan/view/view.html.php +++ b/module/productplan/view/view.html.php @@ -1,84 +1,84 @@ - - * @package productplan - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - -
          title . $lang->colon . $lang->productplan->view;?>
          productplan->title;?>deleted) echo "class='deleted'";?>>title;?> -
          productplan->begin;?>begin;?> -
          productplan->end;?>end;?> -
          productplan->desc;?>desc;?> -
          -
          - session->productPlanList ? $this->session->productPlanList : inlink('browse', "planID=$plan->id"); - if(!$plan->deleted) - { - common::printLink('productplan', 'edit', "planID=$plan->id", $lang->edit); - common::printLink('productplan', 'linkstory',"planID=$plan->id", $lang->productplan->linkStory); - common::printLink('productplan', 'delete', "planID=$plan->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - - - - - - - - - - - - - - - - - - - - createLink('story', 'view', "storyID=$story->id"); - $totalEstimate += $story->estimate; - ?> - - - - - - - - - - - - - - -
          title .$lang->colon . $lang->productplan->linkedStories;?>
          idAB;?>priAB;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions?>
          id);?>pri;?>title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>id", $lang->productplan->unlinkStory, 'hiddenwin');?>
          product->storySummary, count($planStories), $totalEstimate);?>
          - + + * @package productplan + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + +
          title . $lang->colon . $lang->productplan->view;?>
          productplan->title;?>deleted) echo "class='deleted'";?>>title;?> +
          productplan->begin;?>begin;?> +
          productplan->end;?>end;?> +
          productplan->desc;?>desc;?> +
          +
          + session->productPlanList ? $this->session->productPlanList : inlink('browse', "planID=$plan->id"); + if(!$plan->deleted) + { + common::printLink('productplan', 'edit', "planID=$plan->id", $lang->edit); + common::printLink('productplan', 'linkstory',"planID=$plan->id", $lang->productplan->linkStory); + common::printLink('productplan', 'delete', "planID=$plan->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + + + + + + + + + + + + + + + + + + + + createLink('story', 'view', "storyID=$story->id"); + $totalEstimate += $story->estimate; + ?> + + + + + + + + + + + + + + +
          title .$lang->colon . $lang->productplan->linkedStories;?>
          idAB;?>priAB;?>story->title;?>openedByAB;?>assignedToAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>actions?>
          id);?>pri;?>title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>id", $lang->productplan->unlinkStory, 'hiddenwin');?>
          product->storySummary, count($planStories), $totalEstimate);?>
          + diff --git a/module/project/control.php b/module/project/control.php index 6343d09e3c..a5429c3fad 100644 --- a/module/project/control.php +++ b/module/project/control.php @@ -1,1254 +1,1254 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -class project extends control -{ - private $projects; - - /** - * Construct function, Set projects. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - if($this->methodName != 'computeburn') - { - $this->projects = $this->project->getPairs(); - if(!$this->projects and $this->methodName != 'create') $this->locate($this->createLink('project', 'create')); - } - } - - /** - * The index page. - * - * @param string $locate yes|no locate to the browse page or not. - * @param string $status the projects status, if locate is no, then get projects by the $status. - * @access public - * @return void - */ - public function index($locate = 'yes', $status = 'undone') - { - if(empty($this->projects)) $this->locate($this->createLink('project', 'create')); - if($locate == 'yes') $this->locate($this->createLink('project', 'browse')); - - $this->app->loadLang('my'); - $this->view->projectStats = $this->project->getProjectStats($status); - - $this->display(); - } - - /** - * Browse a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function browse($projectID = 0) - { - $this->locate($this->createLink($this->moduleName, 'task', "projectID=$projectID")); - } - - /** - * Common actions. - * - * @param int $projectID - * @access public - * @return object current object - */ - public function commonAction($projectID = 0) - { - $this->loadModel('product'); - - /* Get projects and products info. */ - $projectID = $this->project->saveState($projectID, array_keys($this->projects)); - $project = $this->project->getById($projectID); - $products = $this->project->getProducts($project->id); - $childProjects = $this->project->getChildProjects($project->id); - $teamMembers = $this->project->getTeamMembers($project->id); - - /* Set menu. */ - $this->project->setMenu($this->projects, $project->id); - - /* Assign. */ - $this->view->projects = $this->projects; - $this->view->project = $project; - $this->view->childProjects = $childProjects; - $this->view->products = $products; - $this->view->teamMembers = $teamMembers; - - return $project; - } - - /** - * Tasks of a project. - * - * @param int $projectID - * @param string $status - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function task($projectID = 0, $status = 'all', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 100, $pageID = 1) - { - /* Set browseType, productID, moduleID and queryID. */ - $browseType = strtolower($status); - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - $project = $this->commonAction($projectID); - $projectID = $project->id; - - /* Save to session. */ - $uri = $this->app->getURI(true); - $this->app->session->set('taskList', $uri); - $this->app->session->set('storyList', $uri); - $this->app->session->set('projectList', $uri); - - /* Process the order by field. */ - if(!$orderBy) $orderBy = $this->cookie->projectTaskOrder ? $this->cookie->projectTaskOrder : 'status,id_desc'; - setcookie('projectTaskOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); - - /* Header and position. */ - $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->task; - $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $this->view->position[] = $this->lang->project->task; - - /* Load pager and get tasks. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); - - $tasks = array(); - if($browseType != "bysearch") - { - $tasks = $this->loadModel('task')->getProjectTasks($projectID, $status, $orderBy, $pager); - } - else - { - if($queryID) - { - $query = $this->loadModel('search')->getQuery($queryID); - if($query) - { - $this->session->set('taskQuery', $query->sql); - $this->session->set('taskForm', $query->form); - } - else - { - $this->session->set('taskQuery', ' 1 = 1'); - } - } - else - { - if($this->session->taskQuery == false) $this->session->set('taskQuery', ' 1 = 1'); - } - $taskQuery = str_replace("`project` = 'all'", '1', $this->session->taskQuery); // Search all project. - $this->session->set('taskReportCondition', $taskQuery); - $tasks = $this->project->getSearchTasks($taskQuery, $pager, $orderBy); - } - - /* Build the search form. */ - $this->config->project->search['actionURL'] = $this->createLink('project', 'task', "projectID=$projectID&status=bySearch¶m=myQueryID"); - $this->config->project->search['queryID'] = $queryID; - $this->config->project->search['params']['project']['values'] = array(''=>'', $projectID => $this->projects[$projectID], 'all' => $this->lang->project->allProject); - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->project->search); - - /* Assign. */ - $this->view->tasks = $tasks; - $this->view->tabID = 'task'; - $this->view->pager = $pager; - $this->view->recTotal = $pager->recTotal; - $this->view->recPerPage = $pager->recPerPage; - $this->view->orderBy = $orderBy; - $this->view->browseType = $browseType; - $this->view->status = $status; - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->param = $param; - $this->view->projectID = $projectID; - - $this->display(); - } - - /** - * Browse tasks in group. - * - * @param int $projectID - * @param string $groupBy the field to group by - * @access public - * @return void - */ - public function grouptask($projectID = 0, $groupBy = 'story') - { - $project = $this->commonAction($projectID); - $projectID = $project->id; - - /* Save session. */ - $this->app->session->set('taskList', $this->app->getURI(true)); - $this->app->session->set('storyList', $this->app->getURI(true)); - - /* Header and session. */ - $this->view->header['title'] = $project->name . $this->lang->colon . $this->lang->project->task; - $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $this->view->position[] = $this->lang->project->task; - - /* Get tasks and group them. */ - $tasks = $this->loadModel('task')->getProjectTasks($projectID, $status = 'all', $groupBy ? $groupBy : 'story'); - $groupBy = strtolower(str_replace('`', '', $groupBy)); - - $taskLang = $this->lang->task; - $groupByList = array(); - $groupTasks = array(); - - /* Get users. */ - $users = $this->loadModel('user')->getPairs('noletter'); - foreach($tasks as $task) - { - if($groupBy == '') - { - $groupTasks[$task->story][] = $task; - $groupByList[$task->story] = $task->storyTitle; - } - elseif($groupBy == 'story') - { - $groupTasks[$task->story][] = $task; - $groupByList[$task->story] = $task->storyTitle; - } - elseif($groupBy == 'status') - { - $groupTasks[$taskLang->statusList[$task->status]][] = $task; - } - elseif($groupBy == 'assignedto') - { - $groupTasks[$task->assignedToRealName][] = $task; - } - elseif($groupBy == 'openedby') - { - $groupTasks[$users[$task->openedBy]][] = $task; - } - elseif($groupBy == 'finishedby') - { - $groupTasks[$users[$task->finishedBy]][] = $task; - } - elseif($groupBy == 'closedby') - { - $groupTasks[$users[$task->closedBy]][] = $task; - } - elseif($groupBy == 'type') - { - $groupTasks[$taskLang->typeList[$task->type]][] = $task; - } - else - { - $groupTasks[$task->$groupBy][] = $task; - } - } - - /* Assign. */ - $this->view->members = $this->project->getTeamMembers($projectID); - $this->view->tasks = $groupTasks; - $this->view->tabID = 'task'; - $this->view->groupByList = $groupByList; - $this->view->browseType = 'group'; - $this->view->groupBy = $groupBy; - $this->view->orderBy = $groupBy; - $this->view->projectID = $projectID; - $this->view->users = $users; - $this->display(); - } - - /** - * Import tasks undoned from other projects. - * - * @param int $projectID - * @access public - * @return void - */ - public function importTask($projectID) - { - if(!empty($_POST)) - { - $this->project->importTask($projectID); - die(js::locate(inlink('task', "projectID=$projectID"), 'parent')); - } - - $project = $this->commonAction($projectID); - - /* Save session. */ - $this->app->session->set('taskList', $this->app->getURI(true)); - $this->app->session->set('storyList', $this->app->getURI(true)); - - $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->importTask; - $this->view->position[] = html::a(inlink('browse', "projectID=$projectID"), $project->name); - $this->view->position[] = $this->lang->project->importTask; - $this->view->tasks2Imported = $this->project->getTasks2Imported($projectID); - $this->view->projects = $this->project->getPairs('all'); - $this->display(); - } - - /** - * Import from Bug. - * - * @param int $projectID - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function importBug($projectID = 0, $browseType = 'all', $param = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1) - { - if(!empty($_POST)) - { - $mails = $this->project->importBug($projectID); - if(dao::isError()) die(js::error(dao::getError())); - - foreach($mails as $mail) $this->sendmail($mail->taskID, $mail->actionID); - - /* Locate the browser. */ - die(js::locate($this->createLink('project', 'importBug', "projectID=$projectID"), 'parent')); - } - - /* Set browseType, productID, moduleID and queryID. */ - $browseType = strtolower($browseType); - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Save to session. */ - $uri = $this->app->getURI(true); - $this->app->session->set('bugList', $uri); - $this->app->session->set('storyList', $uri); - $this->app->session->set('projectList', $uri); - - $this->loadModel('bug'); - $projects = $this->project->getPairs(); - $this->project->setMenu($projects, $projectID); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); - - $header['title'] = $projects[$projectID] . $this->lang->colon . $this->lang->project->importBug; - $position[] = html::a($this->createLink('project', 'task', "projectID=$projectID"), $projects[$projectID]); - $position[] = $this->lang->project->importBug; - - /* Get users, products and projects.*/ - $users = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); - $products = $this->dao->select('t1.product, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product = t2.id') - ->where('t1.project')->eq($projectID) - ->fetchPairs('product'); - if(!empty($products)) - { - unset($projects); - $projects = $this->dao->select('t1.project, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2') - ->on('t1.project = t2.id') - ->where('t1.product')->in(array_keys($products)) - ->fetchPairs('project'); - } - else - { - $projectName = $projects[$projectID]; - unset($projects); - $projects[$projectID] = $projectName; - } - - /* Get bugs.*/ - $bugs = array(); - if($browseType != "bysearch") - { - $bugs = $this->bug->getActiveBugs($pager, $projectID, array_keys($products)); - } - else - { - if($queryID) - { - $query = $this->loadModel('search')->getQuery($queryID); - if($query) - { - $this->session->set('bugQuery', $query->sql); - $this->session->set('bugForm', $query->form); - } - else - { - $this->session->set('bugQuery', ' 1 = 1'); - } - } - else - { - if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); - } - $bugQuery = str_replace("`product` = 'all'", "`product`" . helper::dbIN(array_keys($products)), $this->session->bugQuery); // Search all project. - $bugs = $this->project->getSearchBugs($products, $projectID, $bugQuery, $pager, 'id_desc'); - } - - /* Build the search form. */ - $this->config->bug->search['actionURL'] = $this->createLink('project', 'importBug', "projectID=$projectID&browseType=bySearch¶m=myQueryID"); - $this->config->bug->search['queryID'] = $queryID; - if(!empty($products)) - { - $this->config->bug->search['params']['product']['values'] = array(''=>'') + $products + array('all'=>$this->lang->project->aboveAllProduct); - } - else - { - $this->config->bug->search['params']['product']['values'] = array(''=>''); - } - $this->config->bug->search['params']['project']['values'] = array(''=>'') + $projects + array('all'=>$this->lang->project->aboveAllProject); - unset($this->config->bug->search['fields']['resolvedBy']); - unset($this->config->bug->search['fields']['closedBy']); - unset($this->config->bug->search['fields']['status']); - unset($this->config->bug->search['fields']['toTask']); - unset($this->config->bug->search['fields']['toStory']); - unset($this->config->bug->search['fields']['severity']); - unset($this->config->bug->search['fields']['resolution']); - unset($this->config->bug->search['fields']['resolvedBuild']); - unset($this->config->bug->search['fields']['resolvedDate']); - unset($this->config->bug->search['fields']['closedDate']); - unset($this->config->bug->search['params']['resolvedBy']); - unset($this->config->bug->search['params']['closedBy']); - unset($this->config->bug->search['params']['status']); - unset($this->config->bug->search['params']['toTask']); - unset($this->config->bug->search['params']['toStory']); - unset($this->config->bug->search['params']['severity']); - unset($this->config->bug->search['params']['resolution']); - unset($this->config->bug->search['params']['resolvedBuild']); - unset($this->config->bug->search['params']['resolvedDate']); - unset($this->config->bug->search['params']['closedDate']); - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search); - - /* Assign. */ - $this->view->header = $header; - $this->view->pager = $pager; - $this->view->bugs = $bugs; - $this->view->recTotal = $pager->recTotal; - $this->view->recPerPage = $pager->recPerPage; - $this->view->browseType = $browseType; - $this->view->param = $param; - $this->view->users = $users; - $this->view->projectID = $projectID; - $this->display(); - } - - /** - * Browse stories of a project. - * - * @param int $projectID - * @param string $orderBy - * @access public - * @return void - */ - public function story($projectID = 0, $orderBy = '') - { - /* Load these models. */ - $this->loadModel('story'); - $this->loadModel('user'); - $this->loadModel('task'); - - /* Save session. */ - $this->app->session->set('storyList', $this->app->getURI(true)); - - /* Process the order by field. */ - if(!$orderBy) $orderBy = $this->cookie->projectStoryOrder ? $this->cookie->projectStoryOrder : 'pri'; - setcookie('projectStoryOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); - - $project = $this->commonAction($projectID); - - /* Header and position. */ - $header['title'] = $project->name . $this->lang->colon . $this->lang->project->story; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $position[] = $this->lang->project->story; - - /* The pager. */ - $stories = $this->story->getProjectStories($projectID, $orderBy); - $storyTasks = $this->task->getStoryTaskCounts(array_keys($stories), $projectID); - $users = $this->user->getPairs('noletter'); - - /* Get project's product. */ - $productID = 0; - $products = $this->loadModel('product')->getProductsByProject($projectID); - if($products) $productID = key($products); - - /* Assign. */ - $this->view->header = $header; - $this->view->position = $position; - $this->view->productID = $productID; - $this->view->stories = $stories; - $this->view->orderBy = $orderBy; - $this->view->storyTasks = $storyTasks; - $this->view->tabID = 'story'; - $this->view->users = $users; - - $this->display(); - } - - /** - * Browse bugs of a project. - * - * @param int $projectID - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function bug($projectID = 0, $orderBy = 'status,id_desc', $build = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Load these two models. */ - $this->loadModel('bug'); - $this->loadModel('user'); - - /* Save session. */ - $this->session->set('bugList', $this->app->getURI(true)); - - $project = $this->commonAction($projectID); - $products = $this->project->getProducts($project->id); - $productID = key($products); // Get the first product for creating bug. - - /* Header and position. */ - $header['title'] = $project->name . $this->lang->colon . $this->lang->project->bug; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $position[] = $this->lang->project->bug; - - /* Load pager and get bugs, user. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); - $bugs = $this->bug->getProjectBugs($projectID, $orderBy, $pager, $build); - $users = $this->user->getPairs('noletter'); - - /* Assign. */ - $this->view->header = $header; - $this->view->position = $position; - $this->view->bugs = $bugs; - $this->view->tabID = 'bug'; - $this->view->build = $this->loadModel('build')->getById($build); - $this->view->buildID = $this->view->build ? $this->view->build->id : 0; - $this->view->pager = $pager; - $this->view->orderBy = $orderBy; - $this->view->users = $users; - $this->view->productID = $productID; - - $this->display(); - } - - /** - * Browse builds of a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function build($projectID = 0) - { - $this->loadModel('testtask'); - $this->session->set('buildList', $this->app->getURI(true)); - - $project = $this->commonAction($projectID); - - /* Header and position. */ - $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->build; - $this->view->position[] = html::a(inlink('browse', "projectID=$projectID"), $project->name); - $this->view->position[] = $this->lang->project->build; - - /* Get builds. */ - $this->view->builds = $this->loadModel('build')->getProjectBuilds((int)$projectID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - - $this->display(); - } - - /** - * Browse test tasks of project. - * - * @param int $projectID - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function testtask($projectID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - $this->loadModel('testtask'); - /* Save session. */ - $this->session->set('testtaskList', $this->app->getURI(true)); - - $project = $this->commonAction($projectID); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - $this->view->header->title = $this->projects[$projectID] . $this->lang->colon . $this->lang->testtask->common; - $this->view->position[] = html::a($this->createLink('project', 'testtask', "projectID=$projectID"), $this->projects[$projectID]); - $this->view->position[] = $this->lang->testtask->common; - $this->view->projectID = $projectID; - $this->view->projectName = $this->projects[$projectID]; - $this->view->pager = $pager; - $this->view->orderBy = $orderBy; - $this->view->tasks = $this->testtask->getProjectTasks($projectID); - $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); - - $this->display(); - } - - /** - * Browse burndown chart of a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function burn($projectID = 0) - { - $this->loadModel('report'); - $project = $this->commonAction($projectID); - - /* Header and position. */ - $header['title'] = $project->name . $this->lang->colon . $this->lang->project->burn; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $position[] = $this->lang->project->burn; - - /* Create charts by flash. */ - //$dataXML = $this->report->createSingleXML($this->project->getBurnData($project->id), $this->lang->project->charts->burn->graph, $this->lang->report->singleColor); - //$charts = $this->report->createJSChart('line', $dataXML, 700, 350); - - /* Create charts by flot. */ - $sets = $this->project->getBurnDataFlot($project->id); - $count = $sets['count']; - unset($sets['count']); - $dataJSON = $this->report->createSingleJSON($sets); - $charts = $this->report->createJSChartFlot($project->name, $dataJSON, $count, 700, 350); - - /* Assign. */ - $this->view->header = $header; - $this->view->position = $position; - $this->view->tabID = 'burn'; - $this->view->charts = $charts; - - $this->display(); - } - - /** - * Get data of burndown chart. - * - * @param int $projectID - * @access public - * @return void - */ - public function burnData($projectID = 0) - { - $this->loadModel('report'); - $sets = $this->project->getBurnData($projectID); - die($this->report->createSingleXML($sets, $this->lang->project->charts->burn->graph)); - } - - /** - * Compute burndown datas. - * - * @param string $reload - * @access public - * @return void - */ - public function computeBurn($reload = 'no') - { - $this->view->burns = $this->project->computeBurn(); - if($reload == 'yes') die(js::reload('parent')); - die($this->display()); - } - - /** - * Browse team of a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function team($projectID = 0) - { - $project = $this->commonAction($projectID); - - $header['title'] = $project->name . $this->lang->colon . $this->lang->project->team; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $position[] = $this->lang->project->team; - - $this->view->header = $header; - $this->view->position = $position; - - $this->display(); - } - - /** - * Docs of a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function doc($projectID) - { - $this->project->setMenu($this->projects, $projectID); - $this->session->set('docList', $this->app->getURI(true)); - - $project = $this->dao->findById($projectID)->from(TABLE_PROJECT)->fetch(); - $this->view->header->title = $this->lang->project->doc; - $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $project->name); - $this->view->position[] = $this->lang->project->doc; - $this->view->project = $project; - $this->view->docs = $this->loadModel('doc')->getProjectDocs($projectID); - $this->view->modules = $this->doc->getProjectModulePairs(); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Create a project. - * - * @access public - * @return void - */ - public function create($projectID = '', $copyProjectID = '') - { - if($projectID) - { - $this->view->tips = $this->fetch('project', 'tips', "projectID=$projectID"); - $this->view->projectID = $projectID; - $this->display(); - exit; - } - - $teamname = ''; - $products = ''; - $whitelist = ''; - $acl = ''; - - if($copyProjectID) - { - $copyProject = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($copyProjectID)->fetch(); - $teamname = $copyProject->team; - $acl = $copyProject->acl; - $whitelist = $copyProject->whitelist; - $products = join(',', array_keys($this->project->getProducts($copyProjectID))); - } - - if(!empty($_POST)) - { - $projectID = $copyProjectID == '' ? $this->project->create() : $this->project->create($copyProjectID); - $this->project->updateProducts($projectID); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('project', $projectID, 'opened'); - die(js::locate($this->createLink('project', 'create', "projectID=$projectID"), 'parent')); - } - - $this->project->setMenu($this->projects, key($this->projects)); - - $this->view->header->title = $this->lang->project->create; - $this->view->position[] = $this->view->header->title; - $this->view->projects = array('' => '') + $this->projects; - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->allProducts = $this->loadModel('product')->getPairs(); - $this->view->teamname = $teamname ; - $this->view->products = $products ; - $this->view->whitelist = $whitelist; - $this->view->acl = $acl ; - $this->display(); - } - - /** - * Edit a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function edit($projectID) - { - $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); - if(!empty($_POST)) - { - $changes = $this->project->update($projectID); - $this->project->updateProducts($projectID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('project', $projectID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate($this->createLink('project', 'view', "projectID=$projectID"), 'parent')); - } - - /* Set menu. */ - $this->project->setMenu($this->projects, $projectID); - - $projects = array('' => '') + $this->projects; - $project = $this->project->getById($projectID); - $managers = $this->project->getDefaultManagers($projectID); - if(empty($project->PO)) $project->PO = $managers->PO; - if(empty($project->PM)) $project->PM = $this->app->user->account; - if(empty($project->QM)) $project->QM = $managers->QM; - if(empty($project->RM)) $project->RM = $managers->RM; - - /* Remove current project from the projects. */ - unset($projects[$projectID]); - - $header['title'] = $this->lang->project->edit . $this->lang->colon . $project->name; - $position[] = html::a($browseProjectLink, $project->name); - $position[] = $this->lang->project->edit; - - $linkedProducts = $this->project->getProducts($project->id); - $linkedProducts = join(',', array_keys($linkedProducts)); - - $this->view->header = $header; - $this->view->position = $position; - $this->view->projects = $projects; - $this->view->project = $project; - $this->view->users = $this->loadModel('user')->getPairs('noclosed,nodeleted'); - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->allProducts = $this->loadModel('product')->getPairs(); - $this->view->linkedProducts = $linkedProducts; - - $this->display(); - } - - /** - * View a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function view($projectID) - { - $project = $this->project->getById($projectID); - if(!$project) die(js::error($this->lang->notFound) . js::locate('back')); - - /* Set menu. */ - $this->project->setMenu($this->projects, $project->id); - - $this->view->header->title = $this->lang->project->view; - $this->view->position[] = $this->view->header->title; - - $this->view->project = $project; - $this->view->products = $this->project->getProducts($project->id); - $this->view->groups = $this->loadModel('group')->getPairs(); - $this->view->actions = $this->loadModel('action')->getList('project', $projectID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - - $this->display(); - } - - /** - * Delete a project. - * - * @param int $projectID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($projectID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm(sprintf($this->lang->project->confirmDelete, $this->projects[$projectID]), $this->createLink('project', 'delete', "projectID=$projectID&confirm=yes")); - exit; - } - else - { - $this->project->delete(TABLE_PROJECT, $projectID); - $this->session->set('project', ''); - die(js::locate(inlink('index'), 'parent')); - } - } - - /** - * Order project - * - * @param int $projectID - * @access public - * @return void - */ - public function order($projectID) - { - if($_POST) - { - $this->project->saveOrder(); - die(js::reload('parent')); - } - $project = $this->commonAction($projectID); - $this->project->setMenu($this->projects, $project->id); - $this->view->projects = $this->project->getList(); - $this->view->projectID = $project->id; - $this->display(); - } - - /** - * Send email. - * - * @param int $taskID - * @param int $actionID - * @access public - * @return void - */ - public function sendmail($taskID, $actionID) - { - /* Set toList and ccList. */ - $task = $this->loadModel('task')->getById($taskID); - $projectName = $this->project->getById($task->project)->name; - $toList = $task->assignedTo; - $ccList = trim($task->mailto, ','); - - if($toList == '') - { - if($ccList == '') return; - if(strpos($ccList, ',') === false) - { - $toList = $ccList; - $ccList = ''; - } - else - { - $commaPos = strpos($ccList, ','); - $toList = substr($ccList, 0, $commaPos); - $ccList = substr($ccList, $commaPos + 1); - } - } - elseif(strtolower($toList) == 'closed') - { - $toList = $task->finishedBy; - } - - /* Get action info. */ - $action = $this->loadModel('action')->getById($actionID); - $history = $this->action->getHistory($actionID); - $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); - - /* Create the email content. */ - $this->view->task = $task; - $this->view->action = $action; - $this->clear(); - $mailContent = $this->parse($this->moduleName, 'sendmail'); - - /* Send emails. */ - $this->loadModel('mail')->send($toList, $projectName . ':' . 'TASK#' . $task->id . $this->lang->colon . $task->name, $mailContent, $ccList); - if($this->mail->isError()) echo js::error($this->mail->getError()); - } - - /** - * Manage products. - * - * @param int $projectID - * @access public - * @return void - */ - public function manageProducts($projectID) - { - $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); - if(!empty($_POST)) - { - $this->project->updateProducts($projectID); - if(dao::isError()) dis(js::error(dao::getError())); - die(js::locate($browseProjectLink)); - } - - $this->loadModel('product'); - $project = $this->project->getById($projectID); - - /* Set menu. */ - $this->project->setMenu($this->projects, $project->id); - - /* Title and position. */ - $header['title'] = $this->lang->project->manageProducts . $this->lang->colon . $project->name; - $position[] = html::a($browseProjectLink, $project->name); - $position[] = $this->lang->project->manageProducts; - - $allProducts = $this->product->getPairs(); - $linkedProducts = $this->project->getProducts($project->id); - $linkedProducts = join(',', array_keys($linkedProducts)); - - /* Assign. */ - $this->view->header = $header; - $this->view->position = $position; - $this->view->allProducts = $allProducts; - $this->view->linkedProducts = $linkedProducts; - - $this->display(); - } - - /** - * Manage childs projects. - * - * @param int $projectID - * @access public - * @return void - */ - public function manageChilds($projectID) - { - $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); - if(!empty($_POST)) - { - $this->project->updateChilds($projectID); - die(js::locate($browseProjectLink)); - } - $project = $this->project->getById($projectID); - $projects = $this->projects; - unset($projects[$projectID]); - unset($projects[$project->parent]); - if(empty($projects)) $this->locate($browseProjectLink); - - /* Header and position. */ - $header['title'] = $this->lang->project->manageChilds . $this->lang->colon . $project->name; - $position[] = html::a($browseProjectLink, $project->name); - $position[] = $this->lang->project->manageChilds; - - $childProjects = $this->project->getChildProjects($project->id); - $childProjects = join(",", array_keys($childProjects)); - - /* Set menu. */ - $this->project->setMenu($this->projects, $project->id); - - /* Assign. */ - $this->view->header = $header; - $this->view->position = $position; - $this->view->projects = $projects; - $this->view->childProjects = $childProjects; - - $this->display(); - } - - /** - * Manage members of the project. - * - * @param int $projectID - * @access public - * @return void - */ - public function manageMembers($projectID = 0) - { - if(!empty($_POST)) - { - $this->project->manageMembers($projectID); - $this->locate($this->createLink('project', 'team', "projectID=$projectID")); - exit; - } - $this->loadModel('user'); - - $project = $this->project->getById($projectID); - $users = $this->user->getPairs('noclosed, nodeleted'); - $users = array('' => '') + $users; - $members = $this->project->getTeamMembers($projectID); - - /* The deleted members. */ - foreach($members as $account => $member) - { - if(!@$users[$member->account]) $member->account .= $this->lang->user->deleted; - } - - /* Set menu. */ - $this->project->setMenu($this->projects, $project->id); - - $header['title'] = $this->lang->project->manageMembers . $this->lang->colon . $project->name; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); - $position[] = $this->lang->project->manageMembers; - $this->view->header = $header; - $this->view->position = $position; - - $this->view->project = $project; - $this->view->users = $users; - $this->view->members = $members; - $this->display(); - } - - /** - * Unlink a memeber. - * - * @param int $projectID - * @param string $account - * @param string $confirm yes|no - * @access public - * @return void - */ - public function unlinkMember($projectID, $account, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->project->confirmUnlinkMember, $this->inlink('unlinkMember', "projectID=$projectID&account=$account&confirm=yes"))); - } - else - { - $this->project->unlinkMember($projectID, $account); - die(js::locate($this->inlink('team', "projectID=$projectID"), 'parent')); - } - } - - /** - * Link stories to a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function linkStory($projectID = 0) - { - /* Get projects and products. */ - $project = $this->project->getById($projectID); - $products = $this->project->getProducts($projectID); - $browseLink = $this->createLink('project', 'story', "projectID=$projectID"); - - $this->session->set('storyList', $this->app->getURI(true)); // Save session. - $this->project->setMenu($this->projects, $project->id); // Set menu. - - if(empty($products)) - { - echo js::alert($this->lang->project->errorNoLinkedProducts); - die(js::locate($this->createLink('project', 'manageproducts', "projectID=$projectID"))); - } - - if(!empty($_POST)) - { - $this->project->linkStory($projectID); - die(js::locate($browseLink, 'parent')); - exit; - } - - $this->loadModel('story'); - - $header['title'] = $project->name . $this->lang->colon . $this->lang->project->linkStory; - $position[] = html::a($browseLink, $project->name); - $position[] = $this->lang->project->linkStory; - - $allStories = $this->story->getProductStories(array_keys($products), $moduleID = '0', $status = 'active'); - $prjStories = $this->story->getProjectStoryPairs($projectID); - - $this->view->header = $header; - $this->view->position = $position; - $this->view->project = $project; - $this->view->products = $products; - $this->view->allStories = $allStories; - $this->view->prjStories = $prjStories; - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Unlink a story. - * - * @param int $projectID - * @param int $storyID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function unlinkStory($projectID, $storyID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->project->confirmUnlinkStory, $this->createLink('project', 'unlinkstory', "projectID=$projectID&storyID=$storyID&confirm=yes")); - exit; - } - else - { - $this->project->unlinkStory($projectID, $storyID); - echo js::locate($this->app->session->storyList, 'parent'); - exit; - } - } - - /** - * Project dynamic. - * - * @param string $type - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function dynamic($projectID = 0, $type = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - /* Set the menu. If the projectID = 0, use the indexMenu instead. */ - $this->project->setMenu($this->projects, $projectID); - if($projectID == 0) - { - $this->projects = array('0' => $this->lang->project->selectProject) + $this->projects; - unset($this->lang->project->menu); - $this->lang->project->menu = $this->lang->project->indexMenu; - $this->lang->project->menu->list = $this->project->select($this->projects, 0, 'project', 'dynamic'); - } - - /* Set the pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - - /* Set the user and type. */ - $account = $type == 'account' ? $param : 'all'; - $period = $type == 'account' ? 'all' : $type; - - /* The header and position. */ - $project = $this->project->getByID($projectID); - $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->dynamic; - $this->view->position[] = $this->lang->project->dynamic; - - /* Assign. */ - $this->view->projectID = $projectID; - $this->view->type = $type; - $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); - $this->view->account = $account; - $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager, 'all', $projectID); - $this->display(); - } - - /** - * AJAX: get products of a project in html select. - * - * @param int $projectID - * @access public - * @return void - */ - public function ajaxGetProducts($projectID) - { - $products = $this->project->getProducts($projectID); - die(html::select('product', $products, '', 'class="select-3"')); - } - - /** - * When create a project, help the user. - * - * @param int $projectID - * @access public - * @return void - */ - public function tips($projectID) - { - $this->view->projectID = $projectID; - $this->display('project', 'tips'); - } -} + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +class project extends control +{ + private $projects; + + /** + * Construct function, Set projects. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + if($this->methodName != 'computeburn') + { + $this->projects = $this->project->getPairs(); + if(!$this->projects and $this->methodName != 'create') $this->locate($this->createLink('project', 'create')); + } + } + + /** + * The index page. + * + * @param string $locate yes|no locate to the browse page or not. + * @param string $status the projects status, if locate is no, then get projects by the $status. + * @access public + * @return void + */ + public function index($locate = 'yes', $status = 'undone') + { + if(empty($this->projects)) $this->locate($this->createLink('project', 'create')); + if($locate == 'yes') $this->locate($this->createLink('project', 'browse')); + + $this->app->loadLang('my'); + $this->view->projectStats = $this->project->getProjectStats($status); + + $this->display(); + } + + /** + * Browse a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function browse($projectID = 0) + { + $this->locate($this->createLink($this->moduleName, 'task', "projectID=$projectID")); + } + + /** + * Common actions. + * + * @param int $projectID + * @access public + * @return object current object + */ + public function commonAction($projectID = 0) + { + $this->loadModel('product'); + + /* Get projects and products info. */ + $projectID = $this->project->saveState($projectID, array_keys($this->projects)); + $project = $this->project->getById($projectID); + $products = $this->project->getProducts($project->id); + $childProjects = $this->project->getChildProjects($project->id); + $teamMembers = $this->project->getTeamMembers($project->id); + + /* Set menu. */ + $this->project->setMenu($this->projects, $project->id); + + /* Assign. */ + $this->view->projects = $this->projects; + $this->view->project = $project; + $this->view->childProjects = $childProjects; + $this->view->products = $products; + $this->view->teamMembers = $teamMembers; + + return $project; + } + + /** + * Tasks of a project. + * + * @param int $projectID + * @param string $status + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function task($projectID = 0, $status = 'all', $param = 0, $orderBy = '', $recTotal = 0, $recPerPage = 100, $pageID = 1) + { + /* Set browseType, productID, moduleID and queryID. */ + $browseType = strtolower($status); + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + $project = $this->commonAction($projectID); + $projectID = $project->id; + + /* Save to session. */ + $uri = $this->app->getURI(true); + $this->app->session->set('taskList', $uri); + $this->app->session->set('storyList', $uri); + $this->app->session->set('projectList', $uri); + + /* Process the order by field. */ + if(!$orderBy) $orderBy = $this->cookie->projectTaskOrder ? $this->cookie->projectTaskOrder : 'status,id_desc'; + setcookie('projectTaskOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); + + /* Header and position. */ + $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->task; + $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->project->task; + + /* Load pager and get tasks. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + $tasks = array(); + if($browseType != "bysearch") + { + $tasks = $this->loadModel('task')->getProjectTasks($projectID, $status, $orderBy, $pager); + } + else + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('taskQuery', $query->sql); + $this->session->set('taskForm', $query->form); + } + else + { + $this->session->set('taskQuery', ' 1 = 1'); + } + } + else + { + if($this->session->taskQuery == false) $this->session->set('taskQuery', ' 1 = 1'); + } + $taskQuery = str_replace("`project` = 'all'", '1', $this->session->taskQuery); // Search all project. + $this->session->set('taskReportCondition', $taskQuery); + $tasks = $this->project->getSearchTasks($taskQuery, $pager, $orderBy); + } + + /* Build the search form. */ + $this->config->project->search['actionURL'] = $this->createLink('project', 'task', "projectID=$projectID&status=bySearch¶m=myQueryID"); + $this->config->project->search['queryID'] = $queryID; + $this->config->project->search['params']['project']['values'] = array(''=>'', $projectID => $this->projects[$projectID], 'all' => $this->lang->project->allProject); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->project->search); + + /* Assign. */ + $this->view->tasks = $tasks; + $this->view->tabID = 'task'; + $this->view->pager = $pager; + $this->view->recTotal = $pager->recTotal; + $this->view->recPerPage = $pager->recPerPage; + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->status = $status; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->param = $param; + $this->view->projectID = $projectID; + + $this->display(); + } + + /** + * Browse tasks in group. + * + * @param int $projectID + * @param string $groupBy the field to group by + * @access public + * @return void + */ + public function grouptask($projectID = 0, $groupBy = 'story') + { + $project = $this->commonAction($projectID); + $projectID = $project->id; + + /* Save session. */ + $this->app->session->set('taskList', $this->app->getURI(true)); + $this->app->session->set('storyList', $this->app->getURI(true)); + + /* Header and session. */ + $this->view->header['title'] = $project->name . $this->lang->colon . $this->lang->project->task; + $this->view->position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->project->task; + + /* Get tasks and group them. */ + $tasks = $this->loadModel('task')->getProjectTasks($projectID, $status = 'all', $groupBy ? $groupBy : 'story'); + $groupBy = strtolower(str_replace('`', '', $groupBy)); + + $taskLang = $this->lang->task; + $groupByList = array(); + $groupTasks = array(); + + /* Get users. */ + $users = $this->loadModel('user')->getPairs('noletter'); + foreach($tasks as $task) + { + if($groupBy == '') + { + $groupTasks[$task->story][] = $task; + $groupByList[$task->story] = $task->storyTitle; + } + elseif($groupBy == 'story') + { + $groupTasks[$task->story][] = $task; + $groupByList[$task->story] = $task->storyTitle; + } + elseif($groupBy == 'status') + { + $groupTasks[$taskLang->statusList[$task->status]][] = $task; + } + elseif($groupBy == 'assignedto') + { + $groupTasks[$task->assignedToRealName][] = $task; + } + elseif($groupBy == 'openedby') + { + $groupTasks[$users[$task->openedBy]][] = $task; + } + elseif($groupBy == 'finishedby') + { + $groupTasks[$users[$task->finishedBy]][] = $task; + } + elseif($groupBy == 'closedby') + { + $groupTasks[$users[$task->closedBy]][] = $task; + } + elseif($groupBy == 'type') + { + $groupTasks[$taskLang->typeList[$task->type]][] = $task; + } + else + { + $groupTasks[$task->$groupBy][] = $task; + } + } + + /* Assign. */ + $this->view->members = $this->project->getTeamMembers($projectID); + $this->view->tasks = $groupTasks; + $this->view->tabID = 'task'; + $this->view->groupByList = $groupByList; + $this->view->browseType = 'group'; + $this->view->groupBy = $groupBy; + $this->view->orderBy = $groupBy; + $this->view->projectID = $projectID; + $this->view->users = $users; + $this->display(); + } + + /** + * Import tasks undoned from other projects. + * + * @param int $projectID + * @access public + * @return void + */ + public function importTask($projectID) + { + if(!empty($_POST)) + { + $this->project->importTask($projectID); + die(js::locate(inlink('task', "projectID=$projectID"), 'parent')); + } + + $project = $this->commonAction($projectID); + + /* Save session. */ + $this->app->session->set('taskList', $this->app->getURI(true)); + $this->app->session->set('storyList', $this->app->getURI(true)); + + $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->importTask; + $this->view->position[] = html::a(inlink('browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->project->importTask; + $this->view->tasks2Imported = $this->project->getTasks2Imported($projectID); + $this->view->projects = $this->project->getPairs('all'); + $this->display(); + } + + /** + * Import from Bug. + * + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function importBug($projectID = 0, $browseType = 'all', $param = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1) + { + if(!empty($_POST)) + { + $mails = $this->project->importBug($projectID); + if(dao::isError()) die(js::error(dao::getError())); + + foreach($mails as $mail) $this->sendmail($mail->taskID, $mail->actionID); + + /* Locate the browser. */ + die(js::locate($this->createLink('project', 'importBug', "projectID=$projectID"), 'parent')); + } + + /* Set browseType, productID, moduleID and queryID. */ + $browseType = strtolower($browseType); + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Save to session. */ + $uri = $this->app->getURI(true); + $this->app->session->set('bugList', $uri); + $this->app->session->set('storyList', $uri); + $this->app->session->set('projectList', $uri); + + $this->loadModel('bug'); + $projects = $this->project->getPairs(); + $this->project->setMenu($projects, $projectID); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + + $header['title'] = $projects[$projectID] . $this->lang->colon . $this->lang->project->importBug; + $position[] = html::a($this->createLink('project', 'task', "projectID=$projectID"), $projects[$projectID]); + $position[] = $this->lang->project->importBug; + + /* Get users, products and projects.*/ + $users = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); + $products = $this->dao->select('t1.product, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product = t2.id') + ->where('t1.project')->eq($projectID) + ->fetchPairs('product'); + if(!empty($products)) + { + unset($projects); + $projects = $this->dao->select('t1.project, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2') + ->on('t1.project = t2.id') + ->where('t1.product')->in(array_keys($products)) + ->fetchPairs('project'); + } + else + { + $projectName = $projects[$projectID]; + unset($projects); + $projects[$projectID] = $projectName; + } + + /* Get bugs.*/ + $bugs = array(); + if($browseType != "bysearch") + { + $bugs = $this->bug->getActiveBugs($pager, $projectID, array_keys($products)); + } + else + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('bugQuery', $query->sql); + $this->session->set('bugForm', $query->form); + } + else + { + $this->session->set('bugQuery', ' 1 = 1'); + } + } + else + { + if($this->session->bugQuery == false) $this->session->set('bugQuery', ' 1 = 1'); + } + $bugQuery = str_replace("`product` = 'all'", "`product`" . helper::dbIN(array_keys($products)), $this->session->bugQuery); // Search all project. + $bugs = $this->project->getSearchBugs($products, $projectID, $bugQuery, $pager, 'id_desc'); + } + + /* Build the search form. */ + $this->config->bug->search['actionURL'] = $this->createLink('project', 'importBug', "projectID=$projectID&browseType=bySearch¶m=myQueryID"); + $this->config->bug->search['queryID'] = $queryID; + if(!empty($products)) + { + $this->config->bug->search['params']['product']['values'] = array(''=>'') + $products + array('all'=>$this->lang->project->aboveAllProduct); + } + else + { + $this->config->bug->search['params']['product']['values'] = array(''=>''); + } + $this->config->bug->search['params']['project']['values'] = array(''=>'') + $projects + array('all'=>$this->lang->project->aboveAllProject); + unset($this->config->bug->search['fields']['resolvedBy']); + unset($this->config->bug->search['fields']['closedBy']); + unset($this->config->bug->search['fields']['status']); + unset($this->config->bug->search['fields']['toTask']); + unset($this->config->bug->search['fields']['toStory']); + unset($this->config->bug->search['fields']['severity']); + unset($this->config->bug->search['fields']['resolution']); + unset($this->config->bug->search['fields']['resolvedBuild']); + unset($this->config->bug->search['fields']['resolvedDate']); + unset($this->config->bug->search['fields']['closedDate']); + unset($this->config->bug->search['params']['resolvedBy']); + unset($this->config->bug->search['params']['closedBy']); + unset($this->config->bug->search['params']['status']); + unset($this->config->bug->search['params']['toTask']); + unset($this->config->bug->search['params']['toStory']); + unset($this->config->bug->search['params']['severity']); + unset($this->config->bug->search['params']['resolution']); + unset($this->config->bug->search['params']['resolvedBuild']); + unset($this->config->bug->search['params']['resolvedDate']); + unset($this->config->bug->search['params']['closedDate']); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->bug->search); + + /* Assign. */ + $this->view->header = $header; + $this->view->pager = $pager; + $this->view->bugs = $bugs; + $this->view->recTotal = $pager->recTotal; + $this->view->recPerPage = $pager->recPerPage; + $this->view->browseType = $browseType; + $this->view->param = $param; + $this->view->users = $users; + $this->view->projectID = $projectID; + $this->display(); + } + + /** + * Browse stories of a project. + * + * @param int $projectID + * @param string $orderBy + * @access public + * @return void + */ + public function story($projectID = 0, $orderBy = '') + { + /* Load these models. */ + $this->loadModel('story'); + $this->loadModel('user'); + $this->loadModel('task'); + + /* Save session. */ + $this->app->session->set('storyList', $this->app->getURI(true)); + + /* Process the order by field. */ + if(!$orderBy) $orderBy = $this->cookie->projectStoryOrder ? $this->cookie->projectStoryOrder : 'pri'; + setcookie('projectStoryOrder', $orderBy, $this->config->cookieLife, $this->config->webRoot); + + $project = $this->commonAction($projectID); + + /* Header and position. */ + $header['title'] = $project->name . $this->lang->colon . $this->lang->project->story; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->lang->project->story; + + /* The pager. */ + $stories = $this->story->getProjectStories($projectID, $orderBy); + $storyTasks = $this->task->getStoryTaskCounts(array_keys($stories), $projectID); + $users = $this->user->getPairs('noletter'); + + /* Get project's product. */ + $productID = 0; + $products = $this->loadModel('product')->getProductsByProject($projectID); + if($products) $productID = key($products); + + /* Assign. */ + $this->view->header = $header; + $this->view->position = $position; + $this->view->productID = $productID; + $this->view->stories = $stories; + $this->view->orderBy = $orderBy; + $this->view->storyTasks = $storyTasks; + $this->view->tabID = 'story'; + $this->view->users = $users; + + $this->display(); + } + + /** + * Browse bugs of a project. + * + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function bug($projectID = 0, $orderBy = 'status,id_desc', $build = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Load these two models. */ + $this->loadModel('bug'); + $this->loadModel('user'); + + /* Save session. */ + $this->session->set('bugList', $this->app->getURI(true)); + + $project = $this->commonAction($projectID); + $products = $this->project->getProducts($project->id); + $productID = key($products); // Get the first product for creating bug. + + /* Header and position. */ + $header['title'] = $project->name . $this->lang->colon . $this->lang->project->bug; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->lang->project->bug; + + /* Load pager and get bugs, user. */ + $this->app->loadClass('pager', $static = true); + $pager = new pager($recTotal, $recPerPage, $pageID); + $bugs = $this->bug->getProjectBugs($projectID, $orderBy, $pager, $build); + $users = $this->user->getPairs('noletter'); + + /* Assign. */ + $this->view->header = $header; + $this->view->position = $position; + $this->view->bugs = $bugs; + $this->view->tabID = 'bug'; + $this->view->build = $this->loadModel('build')->getById($build); + $this->view->buildID = $this->view->build ? $this->view->build->id : 0; + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->users = $users; + $this->view->productID = $productID; + + $this->display(); + } + + /** + * Browse builds of a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function build($projectID = 0) + { + $this->loadModel('testtask'); + $this->session->set('buildList', $this->app->getURI(true)); + + $project = $this->commonAction($projectID); + + /* Header and position. */ + $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->build; + $this->view->position[] = html::a(inlink('browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->project->build; + + /* Get builds. */ + $this->view->builds = $this->loadModel('build')->getProjectBuilds((int)$projectID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Browse test tasks of project. + * + * @param int $projectID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function testtask($projectID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $this->loadModel('testtask'); + /* Save session. */ + $this->session->set('testtaskList', $this->app->getURI(true)); + + $project = $this->commonAction($projectID); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $this->view->header->title = $this->projects[$projectID] . $this->lang->colon . $this->lang->testtask->common; + $this->view->position[] = html::a($this->createLink('project', 'testtask', "projectID=$projectID"), $this->projects[$projectID]); + $this->view->position[] = $this->lang->testtask->common; + $this->view->projectID = $projectID; + $this->view->projectName = $this->projects[$projectID]; + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->tasks = $this->testtask->getProjectTasks($projectID); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); + + $this->display(); + } + + /** + * Browse burndown chart of a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function burn($projectID = 0) + { + $this->loadModel('report'); + $project = $this->commonAction($projectID); + + /* Header and position. */ + $header['title'] = $project->name . $this->lang->colon . $this->lang->project->burn; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->lang->project->burn; + + /* Create charts by flash. */ + //$dataXML = $this->report->createSingleXML($this->project->getBurnData($project->id), $this->lang->project->charts->burn->graph, $this->lang->report->singleColor); + //$charts = $this->report->createJSChart('line', $dataXML, 700, 350); + + /* Create charts by flot. */ + $sets = $this->project->getBurnDataFlot($project->id); + $count = $sets['count']; + unset($sets['count']); + $dataJSON = $this->report->createSingleJSON($sets); + $charts = $this->report->createJSChartFlot($project->name, $dataJSON, $count, 700, 350); + + /* Assign. */ + $this->view->header = $header; + $this->view->position = $position; + $this->view->tabID = 'burn'; + $this->view->charts = $charts; + + $this->display(); + } + + /** + * Get data of burndown chart. + * + * @param int $projectID + * @access public + * @return void + */ + public function burnData($projectID = 0) + { + $this->loadModel('report'); + $sets = $this->project->getBurnData($projectID); + die($this->report->createSingleXML($sets, $this->lang->project->charts->burn->graph)); + } + + /** + * Compute burndown datas. + * + * @param string $reload + * @access public + * @return void + */ + public function computeBurn($reload = 'no') + { + $this->view->burns = $this->project->computeBurn(); + if($reload == 'yes') die(js::reload('parent')); + die($this->display()); + } + + /** + * Browse team of a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function team($projectID = 0) + { + $project = $this->commonAction($projectID); + + $header['title'] = $project->name . $this->lang->colon . $this->lang->project->team; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->lang->project->team; + + $this->view->header = $header; + $this->view->position = $position; + + $this->display(); + } + + /** + * Docs of a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function doc($projectID) + { + $this->project->setMenu($this->projects, $projectID); + $this->session->set('docList', $this->app->getURI(true)); + + $project = $this->dao->findById($projectID)->from(TABLE_PROJECT)->fetch(); + $this->view->header->title = $this->lang->project->doc; + $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $project->name); + $this->view->position[] = $this->lang->project->doc; + $this->view->project = $project; + $this->view->docs = $this->loadModel('doc')->getProjectDocs($projectID); + $this->view->modules = $this->doc->getProjectModulePairs(); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Create a project. + * + * @access public + * @return void + */ + public function create($projectID = '', $copyProjectID = '') + { + if($projectID) + { + $this->view->tips = $this->fetch('project', 'tips', "projectID=$projectID"); + $this->view->projectID = $projectID; + $this->display(); + exit; + } + + $teamname = ''; + $products = ''; + $whitelist = ''; + $acl = ''; + + if($copyProjectID) + { + $copyProject = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($copyProjectID)->fetch(); + $teamname = $copyProject->team; + $acl = $copyProject->acl; + $whitelist = $copyProject->whitelist; + $products = join(',', array_keys($this->project->getProducts($copyProjectID))); + } + + if(!empty($_POST)) + { + $projectID = $copyProjectID == '' ? $this->project->create() : $this->project->create($copyProjectID); + $this->project->updateProducts($projectID); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('project', $projectID, 'opened'); + die(js::locate($this->createLink('project', 'create', "projectID=$projectID"), 'parent')); + } + + $this->project->setMenu($this->projects, key($this->projects)); + + $this->view->header->title = $this->lang->project->create; + $this->view->position[] = $this->view->header->title; + $this->view->projects = array('' => '') + $this->projects; + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->allProducts = $this->loadModel('product')->getPairs(); + $this->view->teamname = $teamname ; + $this->view->products = $products ; + $this->view->whitelist = $whitelist; + $this->view->acl = $acl ; + $this->display(); + } + + /** + * Edit a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function edit($projectID) + { + $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); + if(!empty($_POST)) + { + $changes = $this->project->update($projectID); + $this->project->updateProducts($projectID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('project', $projectID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate($this->createLink('project', 'view', "projectID=$projectID"), 'parent')); + } + + /* Set menu. */ + $this->project->setMenu($this->projects, $projectID); + + $projects = array('' => '') + $this->projects; + $project = $this->project->getById($projectID); + $managers = $this->project->getDefaultManagers($projectID); + if(empty($project->PO)) $project->PO = $managers->PO; + if(empty($project->PM)) $project->PM = $this->app->user->account; + if(empty($project->QM)) $project->QM = $managers->QM; + if(empty($project->RM)) $project->RM = $managers->RM; + + /* Remove current project from the projects. */ + unset($projects[$projectID]); + + $header['title'] = $this->lang->project->edit . $this->lang->colon . $project->name; + $position[] = html::a($browseProjectLink, $project->name); + $position[] = $this->lang->project->edit; + + $linkedProducts = $this->project->getProducts($project->id); + $linkedProducts = join(',', array_keys($linkedProducts)); + + $this->view->header = $header; + $this->view->position = $position; + $this->view->projects = $projects; + $this->view->project = $project; + $this->view->users = $this->loadModel('user')->getPairs('noclosed,nodeleted'); + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->allProducts = $this->loadModel('product')->getPairs(); + $this->view->linkedProducts = $linkedProducts; + + $this->display(); + } + + /** + * View a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function view($projectID) + { + $project = $this->project->getById($projectID); + if(!$project) die(js::error($this->lang->notFound) . js::locate('back')); + + /* Set menu. */ + $this->project->setMenu($this->projects, $project->id); + + $this->view->header->title = $this->lang->project->view; + $this->view->position[] = $this->view->header->title; + + $this->view->project = $project; + $this->view->products = $this->project->getProducts($project->id); + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->actions = $this->loadModel('action')->getList('project', $projectID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Delete a project. + * + * @param int $projectID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($projectID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm(sprintf($this->lang->project->confirmDelete, $this->projects[$projectID]), $this->createLink('project', 'delete', "projectID=$projectID&confirm=yes")); + exit; + } + else + { + $this->project->delete(TABLE_PROJECT, $projectID); + $this->session->set('project', ''); + die(js::locate(inlink('index'), 'parent')); + } + } + + /** + * Order project + * + * @param int $projectID + * @access public + * @return void + */ + public function order($projectID) + { + if($_POST) + { + $this->project->saveOrder(); + die(js::reload('parent')); + } + $project = $this->commonAction($projectID); + $this->project->setMenu($this->projects, $project->id); + $this->view->projects = $this->project->getList(); + $this->view->projectID = $project->id; + $this->display(); + } + + /** + * Send email. + * + * @param int $taskID + * @param int $actionID + * @access public + * @return void + */ + public function sendmail($taskID, $actionID) + { + /* Set toList and ccList. */ + $task = $this->loadModel('task')->getById($taskID); + $projectName = $this->project->getById($task->project)->name; + $toList = $task->assignedTo; + $ccList = trim($task->mailto, ','); + + if($toList == '') + { + if($ccList == '') return; + if(strpos($ccList, ',') === false) + { + $toList = $ccList; + $ccList = ''; + } + else + { + $commaPos = strpos($ccList, ','); + $toList = substr($ccList, 0, $commaPos); + $ccList = substr($ccList, $commaPos + 1); + } + } + elseif(strtolower($toList) == 'closed') + { + $toList = $task->finishedBy; + } + + /* Get action info. */ + $action = $this->loadModel('action')->getById($actionID); + $history = $this->action->getHistory($actionID); + $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); + + /* Create the email content. */ + $this->view->task = $task; + $this->view->action = $action; + $this->clear(); + $mailContent = $this->parse($this->moduleName, 'sendmail'); + + /* Send emails. */ + $this->loadModel('mail')->send($toList, $projectName . ':' . 'TASK#' . $task->id . $this->lang->colon . $task->name, $mailContent, $ccList); + if($this->mail->isError()) echo js::error($this->mail->getError()); + } + + /** + * Manage products. + * + * @param int $projectID + * @access public + * @return void + */ + public function manageProducts($projectID) + { + $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); + if(!empty($_POST)) + { + $this->project->updateProducts($projectID); + if(dao::isError()) dis(js::error(dao::getError())); + die(js::locate($browseProjectLink)); + } + + $this->loadModel('product'); + $project = $this->project->getById($projectID); + + /* Set menu. */ + $this->project->setMenu($this->projects, $project->id); + + /* Title and position. */ + $header['title'] = $this->lang->project->manageProducts . $this->lang->colon . $project->name; + $position[] = html::a($browseProjectLink, $project->name); + $position[] = $this->lang->project->manageProducts; + + $allProducts = $this->product->getPairs(); + $linkedProducts = $this->project->getProducts($project->id); + $linkedProducts = join(',', array_keys($linkedProducts)); + + /* Assign. */ + $this->view->header = $header; + $this->view->position = $position; + $this->view->allProducts = $allProducts; + $this->view->linkedProducts = $linkedProducts; + + $this->display(); + } + + /** + * Manage childs projects. + * + * @param int $projectID + * @access public + * @return void + */ + public function manageChilds($projectID) + { + $browseProjectLink = $this->createLink('project', 'browse', "projectID=$projectID"); + if(!empty($_POST)) + { + $this->project->updateChilds($projectID); + die(js::locate($browseProjectLink)); + } + $project = $this->project->getById($projectID); + $projects = $this->projects; + unset($projects[$projectID]); + unset($projects[$project->parent]); + if(empty($projects)) $this->locate($browseProjectLink); + + /* Header and position. */ + $header['title'] = $this->lang->project->manageChilds . $this->lang->colon . $project->name; + $position[] = html::a($browseProjectLink, $project->name); + $position[] = $this->lang->project->manageChilds; + + $childProjects = $this->project->getChildProjects($project->id); + $childProjects = join(",", array_keys($childProjects)); + + /* Set menu. */ + $this->project->setMenu($this->projects, $project->id); + + /* Assign. */ + $this->view->header = $header; + $this->view->position = $position; + $this->view->projects = $projects; + $this->view->childProjects = $childProjects; + + $this->display(); + } + + /** + * Manage members of the project. + * + * @param int $projectID + * @access public + * @return void + */ + public function manageMembers($projectID = 0) + { + if(!empty($_POST)) + { + $this->project->manageMembers($projectID); + $this->locate($this->createLink('project', 'team', "projectID=$projectID")); + exit; + } + $this->loadModel('user'); + + $project = $this->project->getById($projectID); + $users = $this->user->getPairs('noclosed, nodeleted'); + $users = array('' => '') + $users; + $members = $this->project->getTeamMembers($projectID); + + /* The deleted members. */ + foreach($members as $account => $member) + { + if(!@$users[$member->account]) $member->account .= $this->lang->user->deleted; + } + + /* Set menu. */ + $this->project->setMenu($this->projects, $project->id); + + $header['title'] = $this->lang->project->manageMembers . $this->lang->colon . $project->name; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$projectID"), $project->name); + $position[] = $this->lang->project->manageMembers; + $this->view->header = $header; + $this->view->position = $position; + + $this->view->project = $project; + $this->view->users = $users; + $this->view->members = $members; + $this->display(); + } + + /** + * Unlink a memeber. + * + * @param int $projectID + * @param string $account + * @param string $confirm yes|no + * @access public + * @return void + */ + public function unlinkMember($projectID, $account, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->project->confirmUnlinkMember, $this->inlink('unlinkMember', "projectID=$projectID&account=$account&confirm=yes"))); + } + else + { + $this->project->unlinkMember($projectID, $account); + die(js::locate($this->inlink('team', "projectID=$projectID"), 'parent')); + } + } + + /** + * Link stories to a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function linkStory($projectID = 0) + { + /* Get projects and products. */ + $project = $this->project->getById($projectID); + $products = $this->project->getProducts($projectID); + $browseLink = $this->createLink('project', 'story', "projectID=$projectID"); + + $this->session->set('storyList', $this->app->getURI(true)); // Save session. + $this->project->setMenu($this->projects, $project->id); // Set menu. + + if(empty($products)) + { + echo js::alert($this->lang->project->errorNoLinkedProducts); + die(js::locate($this->createLink('project', 'manageproducts', "projectID=$projectID"))); + } + + if(!empty($_POST)) + { + $this->project->linkStory($projectID); + die(js::locate($browseLink, 'parent')); + exit; + } + + $this->loadModel('story'); + + $header['title'] = $project->name . $this->lang->colon . $this->lang->project->linkStory; + $position[] = html::a($browseLink, $project->name); + $position[] = $this->lang->project->linkStory; + + $allStories = $this->story->getProductStories(array_keys($products), $moduleID = '0', $status = 'active'); + $prjStories = $this->story->getProjectStoryPairs($projectID); + + $this->view->header = $header; + $this->view->position = $position; + $this->view->project = $project; + $this->view->products = $products; + $this->view->allStories = $allStories; + $this->view->prjStories = $prjStories; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Unlink a story. + * + * @param int $projectID + * @param int $storyID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function unlinkStory($projectID, $storyID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->project->confirmUnlinkStory, $this->createLink('project', 'unlinkstory', "projectID=$projectID&storyID=$storyID&confirm=yes")); + exit; + } + else + { + $this->project->unlinkStory($projectID, $storyID); + echo js::locate($this->app->session->storyList, 'parent'); + exit; + } + } + + /** + * Project dynamic. + * + * @param string $type + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dynamic($projectID = 0, $type = 'today', $param = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + /* Set the menu. If the projectID = 0, use the indexMenu instead. */ + $this->project->setMenu($this->projects, $projectID); + if($projectID == 0) + { + $this->projects = array('0' => $this->lang->project->selectProject) + $this->projects; + unset($this->lang->project->menu); + $this->lang->project->menu = $this->lang->project->indexMenu; + $this->lang->project->menu->list = $this->project->select($this->projects, 0, 'project', 'dynamic'); + } + + /* Set the pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + + /* Set the user and type. */ + $account = $type == 'account' ? $param : 'all'; + $period = $type == 'account' ? 'all' : $type; + + /* The header and position. */ + $project = $this->project->getByID($projectID); + $this->view->header->title = $project->name . $this->lang->colon . $this->lang->project->dynamic; + $this->view->position[] = $this->lang->project->dynamic; + + /* Assign. */ + $this->view->projectID = $projectID; + $this->view->type = $type; + $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); + $this->view->account = $account; + $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager, 'all', $projectID); + $this->display(); + } + + /** + * AJAX: get products of a project in html select. + * + * @param int $projectID + * @access public + * @return void + */ + public function ajaxGetProducts($projectID) + { + $products = $this->project->getProducts($projectID); + die(html::select('product', $products, '', 'class="select-3"')); + } + + /** + * When create a project, help the user. + * + * @param int $projectID + * @access public + * @return void + */ + public function tips($projectID) + { + $this->view->projectID = $projectID; + $this->display('project', 'tips'); + } +} diff --git a/module/project/lang/en.php b/module/project/lang/en.php index 5bea1ec0e1..546edfb1ca 100644 --- a/module/project/lang/en.php +++ b/module/project/lang/en.php @@ -1,168 +1,168 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -/* Fields. */ -$lang->project->common = 'Project'; -$lang->project->id = 'ID'; -$lang->project->company = 'Company'; -$lang->project->iscat = 'Is category'; -$lang->project->type = 'Type'; -$lang->project->parent = 'Parent'; -$lang->project->name = 'Name'; -$lang->project->code = 'Code'; -$lang->project->begin = 'Begin'; -$lang->project->end = 'End'; -$lang->project->days = 'Workdays'; -$lang->project->status = 'Status'; -$lang->project->statge = 'Stage'; -$lang->project->pri = 'Priority'; -$lang->project->desc = 'Desc'; -$lang->project->goal = 'Goal'; -$lang->project->openedBy = 'Opened by'; -$lang->project->openedDate = 'Opened date'; -$lang->project->closedBy = 'Closed by'; -$lang->project->closedDate = 'Closed date'; -$lang->project->canceledBy = 'Canceled by'; -$lang->project->canceledDate = 'Canceled date'; -$lang->project->PO = 'Product owner'; -$lang->project->PM = 'Project manager'; -$lang->project->QM = 'Test manager'; -$lang->project->RM = 'Release manager'; -$lang->project->acl = 'Access limitation'; -$lang->project->teamname = 'Team name'; -$lang->project->order = 'Project order'; -$lang->project->products = 'Products'; -$lang->project->childProjects = 'Child projects'; -$lang->project->whitelist = 'Whitelist'; -$lang->project->totalEstimate = 'Est'; -$lang->project->totalConsumed = 'Done'; -$lang->project->totalLeft = 'Left'; -$lang->project->progess = 'Progess'; -$lang->project->viewBug = 'View bug'; -$lang->project->testtaskBrowse= 'Testtask browse'; -$lang->project->createTesttask= 'Create testtask'; -$lang->project->noProduct = 'No product'; -$lang->project->select = '--select project--'; - -$lang->team->account = 'Account'; -$lang->team->role = 'Role'; -$lang->team->join = 'Join date'; -$lang->team->hours = 'Hour/Day'; -$lang->team->days = 'Workdays'; -$lang->team->totalHours = 'Total'; - -/* Lists. */ -$lang->project->statusList[''] = ''; -$lang->project->statusList['wait'] = 'Pending'; -$lang->project->statusList['doing'] = 'Progressing'; -$lang->project->statusList['done'] = 'Done'; - -$lang->project->aclList['open'] = 'Default(Having the priviledge of project module can visit this project)'; -$lang->project->aclList['private'] = 'Private(Only team members can visit)'; -$lang->project->aclList['custom'] = 'Whitelist(Team members and who belongs to the whitelist grups can visit)'; - -/* Methods.*/ -$lang->project->index = "Index"; -$lang->project->task = 'Task'; -$lang->project->groupTask = 'View task by group'; -$lang->project->story = 'Story'; -$lang->project->bug = 'Bug'; -$lang->project->dynamic = 'Dynamic'; -$lang->project->build = 'Build'; -$lang->project->testtask = 'Testtask'; -$lang->project->burn = 'Burndown chart'; -$lang->project->computeBurn = 'Update burndown'; -$lang->project->burnData = 'Burndown data'; -$lang->project->team = 'Team'; -$lang->project->doc = 'Doc'; -$lang->project->manageProducts = 'Link product'; -$lang->project->linkStory = 'Link story'; -$lang->project->view = "Info"; -$lang->project->create = "Add"; -$lang->project->delete = "Delete"; -$lang->project->browse = "Browse"; -$lang->project->edit = "Edit"; -$lang->project->manageMembers = 'Manage team members'; -$lang->project->unlinkMember = 'Remove member'; -$lang->project->unlinkStory = 'Remove story'; -$lang->project->importTask = 'Import task'; -$lang->project->importBug = 'Import bug'; -$lang->project->ajaxGetProducts = "API: get project's products"; - -/* Browse. */ -$lang->project->allTasks = 'All'; -$lang->project->assignedToMe = 'To me'; -$lang->project->finishedByMe = 'My done'; -$lang->project->statusWait = 'Pending'; -$lang->project->statusDoing = 'Progressing'; -$lang->project->statusUndone = 'Not final'; -$lang->project->statusDone = 'Done'; -$lang->project->statusClosed = 'Closed'; -$lang->project->delayed = 'Delayed'; -$lang->project->groups[''] = 'Group View'; -$lang->project->groups['story'] = 'Group by story'; -$lang->project->groups['status'] = 'Group by status'; -$lang->project->groups['pri'] = 'Group by priority'; -$lang->project->groups['openedby'] = 'Group by openedBy'; -$lang->project->groups['assignedTo'] = 'Group by assignedTo'; -$lang->project->groups['finishedby'] = 'Group by finishedBy'; -$lang->project->groups['closedby'] = 'Group by closedBy'; -$lang->project->groups['estimate'] = 'Group by estimate'; -$lang->project->groups['consumed'] = 'Group by consumed'; -$lang->project->groups['left'] = 'Group by left'; -$lang->project->groups['type'] = 'Group by type'; -$lang->project->groups['deadline'] = 'Group by deadline'; -$lang->project->listTaskNeedConfrim = 'Story changed'; -$lang->project->byQuery = 'Search'; - -/* Browse tabs. */ -$lang->project->allProject = 'All projects'; -$lang->project->aboveAllProduct = 'Above all products'; -$lang->project->aboveAllProject = 'Above all projects'; - -/* Notcie. */ -$lang->project->selectProject = "Select project"; -$lang->project->beginAndEnd = 'Begin and end'; -$lang->project->lblStats = 'Stats'; -$lang->project->stats = 'Total work hours is 『%s』hours,
          Total estimate is『%s』hours,
          Total confused is『%s』hours
          Total left is『%s』hours'; -$lang->project->oneLineStats = "Project『%s』, code is『%s』, products is『%s』,begin from『%s』to 『%s』,total estimate『%s』hours,consumed『%s』hours,left『%s』hours."; -$lang->project->taskSummary = "Total tasks shown: %s. Pending: %s. In progress: %s. Estimate: %s hrs. Consumed: %s hrs. Hours left: %s."; -$lang->project->memberHours = "%s has %s workhours, "; -$lang->project->groupSummary = "%s tasks in this group, wait:%s, doing:%s, estimate %s, consumed %s, left %s hours."; -$lang->project->wbs = "WBS"; -$lang->project->largeBurnChart = 'View large'; -$lang->project->howToUpdateBurn = "How?"; -$lang->project->whyNoStories = "There no active stories to added to this project. Please check the linked product."; -$lang->project->doneProjects = 'Done'; -$lang->project->unDoneProjects = 'Undone'; - -/* Confirm. */ -$lang->project->confirmDelete = 'Are you sure to delete project [%s]?'; -$lang->project->confirmUnlinkMember = 'Are you sure to remove this user from this project?'; -$lang->project->confirmUnlinkStory = 'Are you sure to remove the story from this project?'; -$lang->project->errorNoLinkedProducts = 'There is no linked products, go to the link page.'; -$lang->project->accessDenied = 'Access to this project denied.'; -$lang->project->tips = 'Tips'; -$lang->project->afterInfo = 'Successful and you can do:'; -$lang->project->setTeam = 'Set team'; -$lang->project->linkStory = 'Link story'; -$lang->project->createTask = 'Create task'; -$lang->project->goback = 'Go back(Automatically after 5 seconds)'; - -/* Report. */ -$lang->project->charts->burn->graph->caption = "Burndown chart"; -$lang->project->charts->burn->graph->xAxisName = "Date"; -$lang->project->charts->burn->graph->yAxisName = "HOUR"; -$lang->project->charts->burn->graph->baseFontSize = 12; -$lang->project->charts->burn->graph->formatNumber = 0; -$lang->project->charts->burn->graph->animation = 0; -$lang->project->charts->burn->graph->rotateNames = 1; -$lang->project->charts->burn->graph->showValues = 0; + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +/* Fields. */ +$lang->project->common = 'Project'; +$lang->project->id = 'ID'; +$lang->project->company = 'Company'; +$lang->project->iscat = 'Is category'; +$lang->project->type = 'Type'; +$lang->project->parent = 'Parent'; +$lang->project->name = 'Name'; +$lang->project->code = 'Code'; +$lang->project->begin = 'Begin'; +$lang->project->end = 'End'; +$lang->project->days = 'Workdays'; +$lang->project->status = 'Status'; +$lang->project->statge = 'Stage'; +$lang->project->pri = 'Priority'; +$lang->project->desc = 'Desc'; +$lang->project->goal = 'Goal'; +$lang->project->openedBy = 'Opened by'; +$lang->project->openedDate = 'Opened date'; +$lang->project->closedBy = 'Closed by'; +$lang->project->closedDate = 'Closed date'; +$lang->project->canceledBy = 'Canceled by'; +$lang->project->canceledDate = 'Canceled date'; +$lang->project->PO = 'Product owner'; +$lang->project->PM = 'Project manager'; +$lang->project->QM = 'Test manager'; +$lang->project->RM = 'Release manager'; +$lang->project->acl = 'Access limitation'; +$lang->project->teamname = 'Team name'; +$lang->project->order = 'Project order'; +$lang->project->products = 'Products'; +$lang->project->childProjects = 'Child projects'; +$lang->project->whitelist = 'Whitelist'; +$lang->project->totalEstimate = 'Est'; +$lang->project->totalConsumed = 'Done'; +$lang->project->totalLeft = 'Left'; +$lang->project->progess = 'Progess'; +$lang->project->viewBug = 'View bug'; +$lang->project->testtaskBrowse= 'Testtask browse'; +$lang->project->createTesttask= 'Create testtask'; +$lang->project->noProduct = 'No product'; +$lang->project->select = '--select project--'; + +$lang->team->account = 'Account'; +$lang->team->role = 'Role'; +$lang->team->join = 'Join date'; +$lang->team->hours = 'Hour/Day'; +$lang->team->days = 'Workdays'; +$lang->team->totalHours = 'Total'; + +/* Lists. */ +$lang->project->statusList[''] = ''; +$lang->project->statusList['wait'] = 'Pending'; +$lang->project->statusList['doing'] = 'Progressing'; +$lang->project->statusList['done'] = 'Done'; + +$lang->project->aclList['open'] = 'Default(Having the priviledge of project module can visit this project)'; +$lang->project->aclList['private'] = 'Private(Only team members can visit)'; +$lang->project->aclList['custom'] = 'Whitelist(Team members and who belongs to the whitelist grups can visit)'; + +/* Methods.*/ +$lang->project->index = "Index"; +$lang->project->task = 'Task'; +$lang->project->groupTask = 'View task by group'; +$lang->project->story = 'Story'; +$lang->project->bug = 'Bug'; +$lang->project->dynamic = 'Dynamic'; +$lang->project->build = 'Build'; +$lang->project->testtask = 'Testtask'; +$lang->project->burn = 'Burndown chart'; +$lang->project->computeBurn = 'Update burndown'; +$lang->project->burnData = 'Burndown data'; +$lang->project->team = 'Team'; +$lang->project->doc = 'Doc'; +$lang->project->manageProducts = 'Link product'; +$lang->project->linkStory = 'Link story'; +$lang->project->view = "Info"; +$lang->project->create = "Add"; +$lang->project->delete = "Delete"; +$lang->project->browse = "Browse"; +$lang->project->edit = "Edit"; +$lang->project->manageMembers = 'Manage team members'; +$lang->project->unlinkMember = 'Remove member'; +$lang->project->unlinkStory = 'Remove story'; +$lang->project->importTask = 'Import task'; +$lang->project->importBug = 'Import bug'; +$lang->project->ajaxGetProducts = "API: get project's products"; + +/* Browse. */ +$lang->project->allTasks = 'All'; +$lang->project->assignedToMe = 'To me'; +$lang->project->finishedByMe = 'My done'; +$lang->project->statusWait = 'Pending'; +$lang->project->statusDoing = 'Progressing'; +$lang->project->statusUndone = 'Not final'; +$lang->project->statusDone = 'Done'; +$lang->project->statusClosed = 'Closed'; +$lang->project->delayed = 'Delayed'; +$lang->project->groups[''] = 'Group View'; +$lang->project->groups['story'] = 'Group by story'; +$lang->project->groups['status'] = 'Group by status'; +$lang->project->groups['pri'] = 'Group by priority'; +$lang->project->groups['openedby'] = 'Group by openedBy'; +$lang->project->groups['assignedTo'] = 'Group by assignedTo'; +$lang->project->groups['finishedby'] = 'Group by finishedBy'; +$lang->project->groups['closedby'] = 'Group by closedBy'; +$lang->project->groups['estimate'] = 'Group by estimate'; +$lang->project->groups['consumed'] = 'Group by consumed'; +$lang->project->groups['left'] = 'Group by left'; +$lang->project->groups['type'] = 'Group by type'; +$lang->project->groups['deadline'] = 'Group by deadline'; +$lang->project->listTaskNeedConfrim = 'Story changed'; +$lang->project->byQuery = 'Search'; + +/* Browse tabs. */ +$lang->project->allProject = 'All projects'; +$lang->project->aboveAllProduct = 'Above all products'; +$lang->project->aboveAllProject = 'Above all projects'; + +/* Notcie. */ +$lang->project->selectProject = "Select project"; +$lang->project->beginAndEnd = 'Begin and end'; +$lang->project->lblStats = 'Stats'; +$lang->project->stats = 'Total work hours is 『%s』hours,
          Total estimate is『%s』hours,
          Total confused is『%s』hours
          Total left is『%s』hours'; +$lang->project->oneLineStats = "Project『%s』, code is『%s』, products is『%s』,begin from『%s』to 『%s』,total estimate『%s』hours,consumed『%s』hours,left『%s』hours."; +$lang->project->taskSummary = "Total tasks shown: %s. Pending: %s. In progress: %s. Estimate: %s hrs. Consumed: %s hrs. Hours left: %s."; +$lang->project->memberHours = "%s has %s workhours, "; +$lang->project->groupSummary = "%s tasks in this group, wait:%s, doing:%s, estimate %s, consumed %s, left %s hours."; +$lang->project->wbs = "WBS"; +$lang->project->largeBurnChart = 'View large'; +$lang->project->howToUpdateBurn = "How?"; +$lang->project->whyNoStories = "There no active stories to added to this project. Please check the linked product."; +$lang->project->doneProjects = 'Done'; +$lang->project->unDoneProjects = 'Undone'; + +/* Confirm. */ +$lang->project->confirmDelete = 'Are you sure to delete project [%s]?'; +$lang->project->confirmUnlinkMember = 'Are you sure to remove this user from this project?'; +$lang->project->confirmUnlinkStory = 'Are you sure to remove the story from this project?'; +$lang->project->errorNoLinkedProducts = 'There is no linked products, go to the link page.'; +$lang->project->accessDenied = 'Access to this project denied.'; +$lang->project->tips = 'Tips'; +$lang->project->afterInfo = 'Successful and you can do:'; +$lang->project->setTeam = 'Set team'; +$lang->project->linkStory = 'Link story'; +$lang->project->createTask = 'Create task'; +$lang->project->goback = 'Go back(Automatically after 5 seconds)'; + +/* Report. */ +$lang->project->charts->burn->graph->caption = "Burndown chart"; +$lang->project->charts->burn->graph->xAxisName = "Date"; +$lang->project->charts->burn->graph->yAxisName = "HOUR"; +$lang->project->charts->burn->graph->baseFontSize = 12; +$lang->project->charts->burn->graph->formatNumber = 0; +$lang->project->charts->burn->graph->animation = 0; +$lang->project->charts->burn->graph->rotateNames = 1; +$lang->project->charts->burn->graph->showValues = 0; diff --git a/module/project/lang/zh-cn.php b/module/project/lang/zh-cn.php index 30e92ddcfc..56eb00e4fd 100644 --- a/module/project/lang/zh-cn.php +++ b/module/project/lang/zh-cn.php @@ -1,168 +1,168 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -/* 字段列表。*/ -$lang->project->common = '项目视图'; -$lang->project->id = '项目编号'; -$lang->project->company = '所属公司'; -$lang->project->iscat = '作为目录'; -$lang->project->type = '项目类型'; -$lang->project->parent = '上级项目'; -$lang->project->name = '项目名称'; -$lang->project->code = '项目代号'; -$lang->project->begin = '开始日期'; -$lang->project->end = '结束日期'; -$lang->project->days = '可用工作日'; -$lang->project->status = '项目状态'; -$lang->project->statge = '所处阶段'; -$lang->project->pri = '优先级'; -$lang->project->desc = '项目描述'; -$lang->project->goal = '项目目标'; -$lang->project->openedBy = '由谁创建'; -$lang->project->openedDate = '创建日期'; -$lang->project->closedBy = '由谁关闭'; -$lang->project->closedDate = '关闭日期'; -$lang->project->canceledBy = '由谁取消'; -$lang->project->canceledDate = '取消日期'; -$lang->project->PO = '产品负责人'; -$lang->project->PM = '项目负责人'; -$lang->project->QM = '测试负责人'; -$lang->project->RM = '发布负责人'; -$lang->project->acl = '访问控制'; -$lang->project->teamname = '团队名称'; -$lang->project->order = '项目排序'; -$lang->project->products = '相关产品'; -$lang->project->childProjects = '子项目'; -$lang->project->whitelist = '分组白名单'; -$lang->project->totalEstimate = '总预计'; -$lang->project->totalConsumed = '总消耗'; -$lang->project->totalLeft = '总剩余'; -$lang->project->progess = '进度'; -$lang->project->viewBug = '查看bug'; -$lang->project->testtaskBrowse= '待测列表'; -$lang->project->createTesttask= '提交测试'; -$lang->project->noProduct = '无产品项目'; -$lang->project->select = '--请选择项目--'; - -$lang->team->account = '用户'; -$lang->team->role = '角色'; -$lang->team->join = '加盟日'; -$lang->team->hours = '可用工时/天'; -$lang->team->days = '可用工日'; -$lang->team->totalHours = '总计'; - -/* 字段取值列表。*/ -$lang->project->statusList[''] = ''; -$lang->project->statusList['wait'] = '未开始'; -$lang->project->statusList['doing'] = '进行中'; -$lang->project->statusList['done'] = '已完成'; - -$lang->project->aclList['open'] = '默认设置(有项目视图权限,即可访问)'; -$lang->project->aclList['private'] = '私有项目(只有项目团队成员才能访问)'; -$lang->project->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)'; - -/* 方法列表。*/ -$lang->project->index = "项目首页"; -$lang->project->task = '任务列表'; -$lang->project->groupTask = '分组浏览任务'; -$lang->project->story = '需求列表'; -$lang->project->bug = 'Bug列表'; -$lang->project->dynamic = '动态'; -$lang->project->build = 'Build列表'; -$lang->project->testtask = '测试申请'; -$lang->project->burn = '燃尽图'; -$lang->project->computeBurn = '更新燃尽图'; -$lang->project->burnData = '燃尽图数据'; -$lang->project->team = '团队成员'; -$lang->project->doc = '文档列表'; -$lang->project->manageProducts = '关联产品'; -$lang->project->linkStory = '关联需求'; -$lang->project->view = "基本信息"; -$lang->project->create = "添加项目"; -$lang->project->delete = "删除项目"; -$lang->project->browse = "浏览项目"; -$lang->project->edit = "编辑项目"; -$lang->project->manageMembers = '团队管理'; -$lang->project->unlinkMember = '移除成员'; -$lang->project->unlinkStory = '移除需求'; -$lang->project->importTask = '导入任务'; -$lang->project->importBug = '导入Bug'; -$lang->project->ajaxGetProducts = '接口:获得项目产品列表'; - -/* 分组浏览。*/ -$lang->project->allTasks = '所有任务'; -$lang->project->assignedToMe = '指派给我'; -$lang->project->finishedByMe = '由我完成'; -$lang->project->statusWait = '未开始'; -$lang->project->statusDoing = '进行中'; -$lang->project->statusUndone = '未完成'; -$lang->project->statusDone = '已完成'; -$lang->project->statusClosed = '已关闭'; -$lang->project->delayed = '已延期'; -$lang->project->groups[''] = '分组查看'; -$lang->project->groups['story'] = '需求分组'; -$lang->project->groups['status'] = '状态分组'; -$lang->project->groups['pri'] = '优先级分组'; -$lang->project->groups['openedby'] = '创建者分组'; -$lang->project->groups['assignedTo'] = '指派给分组'; -$lang->project->groups['finishedby'] = '完成者分组'; -$lang->project->groups['closedby'] = '关闭者分组'; -$lang->project->groups['estimate'] = '预计分组'; -$lang->project->groups['consumed'] = '已消耗分组'; -$lang->project->groups['left'] = '剩余分组'; -$lang->project->groups['type'] = '类型分组'; -$lang->project->groups['deadline'] = '截止分组'; -$lang->project->listTaskNeedConfrim = '需求变动'; -$lang->project->byQuery = '搜索'; - -/* 查询条件列表。*/ -$lang->project->allProject = '所有项目'; -$lang->project->aboveAllProduct = '以上所有产品'; -$lang->project->aboveAllProject = '以上所有项目'; - -/* 页面提示。*/ -$lang->project->selectProject = "请选择项目"; -$lang->project->beginAndEnd = '起止时间'; -$lang->project->lblStats = '工时统计'; -$lang->project->stats = '可用工时%s工时
          总共预计%s工时
          已经消耗%s工时
          预计剩余%s工时'; -$lang->project->oneLineStats = "项目%s, 代号为%s, 相关产品为%s%s开始,%s结束,总预计%s工时,已消耗%s工时,预计剩余%s工时。"; -$lang->project->taskSummary = "本页共 %s 个任务,未开始%s,进行中%s,总预计%s工时,已消耗%s工时,剩余%s工时。"; -$lang->project->memberHours = "%s共有 %s 个可用工时,"; -$lang->project->groupSummary = "本组共 %s 个任务,未开始%s,进行中%s,总预计%s工时,已消耗%s工时,剩余%s工时。"; -$lang->project->wbs = "分解任务"; -$lang->project->largeBurnChart = '点击查看大图'; -$lang->project->howToUpdateBurn = "如何更新?"; -$lang->project->whyNoStories = "看起来没有需求可以关联。请检查下项目关联的产品中有没有需求,而且要确保它们已经审核通过。"; -$lang->project->doneProjects = '已结束'; -$lang->project->unDoneProjects = '未结束'; - -/* 交互提示。*/ -$lang->project->confirmDelete = '您确定删除项目[%s]吗?'; -$lang->project->confirmUnlinkMember = '您确定从该项目中移除该用户吗?'; -$lang->project->confirmUnlinkStory = '您确定从该项目中移除该需求吗?'; -$lang->project->errorNoLinkedProducts = '该项目没有关联的产品,系统将转到产品关联页面'; -$lang->project->accessDenied = '您无权访问该项目!'; -$lang->project->tips = '提示'; -$lang->project->afterInfo = '项目添加成功,您现在可以进行以下操作:'; -$lang->project->setTeam = '设置团队'; -$lang->project->linkStory = '关联需求'; -$lang->project->createTask = '添加任务'; -$lang->project->goback = '返回项目首页(5秒后将自动跳转)'; - -/* 统计。*/ -$lang->project->charts->burn->graph->caption = "燃尽图"; -$lang->project->charts->burn->graph->xAxisName = "日期"; -$lang->project->charts->burn->graph->yAxisName = "HOUR"; -$lang->project->charts->burn->graph->baseFontSize = 12; -$lang->project->charts->burn->graph->formatNumber = 0; -$lang->project->charts->burn->graph->animation = 0; -$lang->project->charts->burn->graph->rotateNames = 1; -$lang->project->charts->burn->graph->showValues = 0; + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +/* 字段列表。*/ +$lang->project->common = '项目视图'; +$lang->project->id = '项目编号'; +$lang->project->company = '所属公司'; +$lang->project->iscat = '作为目录'; +$lang->project->type = '项目类型'; +$lang->project->parent = '上级项目'; +$lang->project->name = '项目名称'; +$lang->project->code = '项目代号'; +$lang->project->begin = '开始日期'; +$lang->project->end = '结束日期'; +$lang->project->days = '可用工作日'; +$lang->project->status = '项目状态'; +$lang->project->statge = '所处阶段'; +$lang->project->pri = '优先级'; +$lang->project->desc = '项目描述'; +$lang->project->goal = '项目目标'; +$lang->project->openedBy = '由谁创建'; +$lang->project->openedDate = '创建日期'; +$lang->project->closedBy = '由谁关闭'; +$lang->project->closedDate = '关闭日期'; +$lang->project->canceledBy = '由谁取消'; +$lang->project->canceledDate = '取消日期'; +$lang->project->PO = '产品负责人'; +$lang->project->PM = '项目负责人'; +$lang->project->QM = '测试负责人'; +$lang->project->RM = '发布负责人'; +$lang->project->acl = '访问控制'; +$lang->project->teamname = '团队名称'; +$lang->project->order = '项目排序'; +$lang->project->products = '相关产品'; +$lang->project->childProjects = '子项目'; +$lang->project->whitelist = '分组白名单'; +$lang->project->totalEstimate = '总预计'; +$lang->project->totalConsumed = '总消耗'; +$lang->project->totalLeft = '总剩余'; +$lang->project->progess = '进度'; +$lang->project->viewBug = '查看bug'; +$lang->project->testtaskBrowse= '待测列表'; +$lang->project->createTesttask= '提交测试'; +$lang->project->noProduct = '无产品项目'; +$lang->project->select = '--请选择项目--'; + +$lang->team->account = '用户'; +$lang->team->role = '角色'; +$lang->team->join = '加盟日'; +$lang->team->hours = '可用工时/天'; +$lang->team->days = '可用工日'; +$lang->team->totalHours = '总计'; + +/* 字段取值列表。*/ +$lang->project->statusList[''] = ''; +$lang->project->statusList['wait'] = '未开始'; +$lang->project->statusList['doing'] = '进行中'; +$lang->project->statusList['done'] = '已完成'; + +$lang->project->aclList['open'] = '默认设置(有项目视图权限,即可访问)'; +$lang->project->aclList['private'] = '私有项目(只有项目团队成员才能访问)'; +$lang->project->aclList['custom'] = '自定义白名单(团队成员和白名单的成员可以访问)'; + +/* 方法列表。*/ +$lang->project->index = "项目首页"; +$lang->project->task = '任务列表'; +$lang->project->groupTask = '分组浏览任务'; +$lang->project->story = '需求列表'; +$lang->project->bug = 'Bug列表'; +$lang->project->dynamic = '动态'; +$lang->project->build = 'Build列表'; +$lang->project->testtask = '测试申请'; +$lang->project->burn = '燃尽图'; +$lang->project->computeBurn = '更新燃尽图'; +$lang->project->burnData = '燃尽图数据'; +$lang->project->team = '团队成员'; +$lang->project->doc = '文档列表'; +$lang->project->manageProducts = '关联产品'; +$lang->project->linkStory = '关联需求'; +$lang->project->view = "基本信息"; +$lang->project->create = "添加项目"; +$lang->project->delete = "删除项目"; +$lang->project->browse = "浏览项目"; +$lang->project->edit = "编辑项目"; +$lang->project->manageMembers = '团队管理'; +$lang->project->unlinkMember = '移除成员'; +$lang->project->unlinkStory = '移除需求'; +$lang->project->importTask = '导入任务'; +$lang->project->importBug = '导入Bug'; +$lang->project->ajaxGetProducts = '接口:获得项目产品列表'; + +/* 分组浏览。*/ +$lang->project->allTasks = '所有任务'; +$lang->project->assignedToMe = '指派给我'; +$lang->project->finishedByMe = '由我完成'; +$lang->project->statusWait = '未开始'; +$lang->project->statusDoing = '进行中'; +$lang->project->statusUndone = '未完成'; +$lang->project->statusDone = '已完成'; +$lang->project->statusClosed = '已关闭'; +$lang->project->delayed = '已延期'; +$lang->project->groups[''] = '分组查看'; +$lang->project->groups['story'] = '需求分组'; +$lang->project->groups['status'] = '状态分组'; +$lang->project->groups['pri'] = '优先级分组'; +$lang->project->groups['openedby'] = '创建者分组'; +$lang->project->groups['assignedTo'] = '指派给分组'; +$lang->project->groups['finishedby'] = '完成者分组'; +$lang->project->groups['closedby'] = '关闭者分组'; +$lang->project->groups['estimate'] = '预计分组'; +$lang->project->groups['consumed'] = '已消耗分组'; +$lang->project->groups['left'] = '剩余分组'; +$lang->project->groups['type'] = '类型分组'; +$lang->project->groups['deadline'] = '截止分组'; +$lang->project->listTaskNeedConfrim = '需求变动'; +$lang->project->byQuery = '搜索'; + +/* 查询条件列表。*/ +$lang->project->allProject = '所有项目'; +$lang->project->aboveAllProduct = '以上所有产品'; +$lang->project->aboveAllProject = '以上所有项目'; + +/* 页面提示。*/ +$lang->project->selectProject = "请选择项目"; +$lang->project->beginAndEnd = '起止时间'; +$lang->project->lblStats = '工时统计'; +$lang->project->stats = '可用工时%s工时
          总共预计%s工时
          已经消耗%s工时
          预计剩余%s工时'; +$lang->project->oneLineStats = "项目%s, 代号为%s, 相关产品为%s%s开始,%s结束,总预计%s工时,已消耗%s工时,预计剩余%s工时。"; +$lang->project->taskSummary = "本页共 %s 个任务,未开始%s,进行中%s,总预计%s工时,已消耗%s工时,剩余%s工时。"; +$lang->project->memberHours = "%s共有 %s 个可用工时,"; +$lang->project->groupSummary = "本组共 %s 个任务,未开始%s,进行中%s,总预计%s工时,已消耗%s工时,剩余%s工时。"; +$lang->project->wbs = "分解任务"; +$lang->project->largeBurnChart = '点击查看大图'; +$lang->project->howToUpdateBurn = "如何更新?"; +$lang->project->whyNoStories = "看起来没有需求可以关联。请检查下项目关联的产品中有没有需求,而且要确保它们已经审核通过。"; +$lang->project->doneProjects = '已结束'; +$lang->project->unDoneProjects = '未结束'; + +/* 交互提示。*/ +$lang->project->confirmDelete = '您确定删除项目[%s]吗?'; +$lang->project->confirmUnlinkMember = '您确定从该项目中移除该用户吗?'; +$lang->project->confirmUnlinkStory = '您确定从该项目中移除该需求吗?'; +$lang->project->errorNoLinkedProducts = '该项目没有关联的产品,系统将转到产品关联页面'; +$lang->project->accessDenied = '您无权访问该项目!'; +$lang->project->tips = '提示'; +$lang->project->afterInfo = '项目添加成功,您现在可以进行以下操作:'; +$lang->project->setTeam = '设置团队'; +$lang->project->linkStory = '关联需求'; +$lang->project->createTask = '添加任务'; +$lang->project->goback = '返回项目首页(5秒后将自动跳转)'; + +/* 统计。*/ +$lang->project->charts->burn->graph->caption = "燃尽图"; +$lang->project->charts->burn->graph->xAxisName = "日期"; +$lang->project->charts->burn->graph->yAxisName = "HOUR"; +$lang->project->charts->burn->graph->baseFontSize = 12; +$lang->project->charts->burn->graph->formatNumber = 0; +$lang->project->charts->burn->graph->animation = 0; +$lang->project->charts->burn->graph->rotateNames = 1; +$lang->project->charts->burn->graph->showValues = 0; diff --git a/module/project/lang/zh-tw.php b/module/project/lang/zh-tw.php index a5f24d24e0..9b9cba252f 100644 --- a/module/project/lang/zh-tw.php +++ b/module/project/lang/zh-tw.php @@ -1,168 +1,168 @@ - - * @package project - * @version $Id: zh-tw.php 2600 2012-02-21 04:35:05Z wyd621@gmail.com $ - * @link http://www.zentao.net - */ -/* 欄位列表。*/ -$lang->project->common = '項目視圖'; -$lang->project->id = '項目編號'; -$lang->project->company = '所屬公司'; -$lang->project->iscat = '作為目錄'; -$lang->project->type = '項目類型'; -$lang->project->parent = '上級項目'; -$lang->project->name = '項目名稱'; -$lang->project->code = '項目代號'; -$lang->project->begin = '開始日期'; -$lang->project->end = '結束日期'; -$lang->project->days = '可用工作日'; -$lang->project->status = '項目狀態'; -$lang->project->statge = '所處階段'; -$lang->project->pri = '優先順序'; -$lang->project->desc = '項目描述'; -$lang->project->goal = '項目目標'; -$lang->project->openedBy = '由誰創建'; -$lang->project->openedDate = '創建日期'; -$lang->project->closedBy = '由誰關閉'; -$lang->project->closedDate = '關閉日期'; -$lang->project->canceledBy = '由誰取消'; -$lang->project->canceledDate = '取消日期'; -$lang->project->PO = '產品負責人'; -$lang->project->PM = '項目負責人'; -$lang->project->QM = '測試負責人'; -$lang->project->RM = '發佈負責人'; -$lang->project->acl = '訪問控制'; -$lang->project->teamname = '團隊名稱'; -$lang->project->order = '項目排序'; -$lang->project->products = '相關產品'; -$lang->project->childProjects = '子項目'; -$lang->project->whitelist = '分組白名單'; -$lang->project->totalEstimate = '總預計'; -$lang->project->totalConsumed = '總消耗'; -$lang->project->totalLeft = '總剩餘'; -$lang->project->progess = '進度'; -$lang->project->viewBug = '查看bug'; -$lang->project->testtaskBrowse= '待測列表'; -$lang->project->createTesttask= '提交測試'; -$lang->project->noProduct = '無產品項目'; -$lang->project->select = '--請選擇項目--'; - -$lang->team->account = '用戶'; -$lang->team->role = '角色'; -$lang->team->join = '加盟日'; -$lang->team->hours = '可用工時/天'; -$lang->team->days = '可用工日'; -$lang->team->totalHours = '總計'; - -/* 欄位取值列表。*/ -$lang->project->statusList[''] = ''; -$lang->project->statusList['wait'] = '未開始'; -$lang->project->statusList['doing'] = '進行中'; -$lang->project->statusList['done'] = '已完成'; - -$lang->project->aclList['open'] = '預設設置(有項目視圖權限,即可訪問)'; -$lang->project->aclList['private'] = '私有項目(只有項目團隊成員才能訪問)'; -$lang->project->aclList['custom'] = '自定義白名單(團隊成員和白名單的成員可以訪問)'; - -/* 方法列表。*/ -$lang->project->index = "項目首頁"; -$lang->project->task = '任務列表'; -$lang->project->groupTask = '分組瀏覽任務'; -$lang->project->story = '需求列表'; -$lang->project->bug = 'Bug列表'; -$lang->project->dynamic = '動態'; -$lang->project->build = 'Build列表'; -$lang->project->testtask = '測試申請'; -$lang->project->burn = '燃盡圖'; -$lang->project->computeBurn = '更新燃盡圖'; -$lang->project->burnData = '燃盡圖數據'; -$lang->project->team = '團隊成員'; -$lang->project->doc = '文檔列表'; -$lang->project->manageProducts = '關聯產品'; -$lang->project->linkStory = '關聯需求'; -$lang->project->view = "基本信息"; -$lang->project->create = "添加項目"; -$lang->project->delete = "刪除項目"; -$lang->project->browse = "瀏覽項目"; -$lang->project->edit = "編輯項目"; -$lang->project->manageMembers = '團隊管理'; -$lang->project->unlinkMember = '移除成員'; -$lang->project->unlinkStory = '移除需求'; -$lang->project->importTask = '導入任務'; -$lang->project->importBug = '導入Bug'; -$lang->project->ajaxGetProducts = '介面:獲得項目產品列表'; - -/* 分組瀏覽。*/ -$lang->project->allTasks = '所有任務'; -$lang->project->assignedToMe = '指派給我'; -$lang->project->finishedByMe = '由我完成'; -$lang->project->statusWait = '未開始'; -$lang->project->statusDoing = '進行中'; -$lang->project->statusUndone = '未完成'; -$lang->project->statusDone = '已完成'; -$lang->project->statusClosed = '已關閉'; -$lang->project->delayed = '已延期'; -$lang->project->groups[''] = '分組查看'; -$lang->project->groups['story'] = '需求分組'; -$lang->project->groups['status'] = '狀態分組'; -$lang->project->groups['pri'] = '優先順序分組'; -$lang->project->groups['openedby'] = '創建者分組'; -$lang->project->groups['assignedTo'] = '指派給分組'; -$lang->project->groups['finishedby'] = '完成者分組'; -$lang->project->groups['closedby'] = '關閉者分組'; -$lang->project->groups['estimate'] = '預計分組'; -$lang->project->groups['consumed'] = '已消耗分組'; -$lang->project->groups['left'] = '剩餘分組'; -$lang->project->groups['type'] = '類型分組'; -$lang->project->groups['deadline'] = '截止分組'; -$lang->project->listTaskNeedConfrim = '需求變動'; -$lang->project->byQuery = '搜索'; - -/* 查詢條件列表。*/ -$lang->project->allProject = '所有項目'; -$lang->project->aboveAllProduct = '以上所有產品'; -$lang->project->aboveAllProject = '以上所有項目'; - -/* 頁面提示。*/ -$lang->project->selectProject = "請選擇項目"; -$lang->project->beginAndEnd = '起止時間'; -$lang->project->lblStats = '工時統計'; -$lang->project->stats = '可用工時%s工時
          總共預計%s工時
          已經消耗%s工時
          預計剩餘%s工時'; -$lang->project->oneLineStats = "項目%s, 代號為%s, 相關產品為%s%s開始,%s結束,總預計%s工時,已消耗%s工時,預計剩餘%s工時。"; -$lang->project->taskSummary = "本頁共 %s 個任務,未開始%s,進行中%s,總預計%s工時,已消耗%s工時,剩餘%s工時。"; -$lang->project->memberHours = "%s共有 %s 個可用工時,"; -$lang->project->groupSummary = "本組共 %s 個任務,未開始%s,進行中%s,總預計%s工時,已消耗%s工時,剩餘%s工時。"; -$lang->project->wbs = "分解任務"; -$lang->project->largeBurnChart = '點擊查看大圖'; -$lang->project->howToUpdateBurn = "如何更新?"; -$lang->project->whyNoStories = "看起來沒有需求可以關聯。請檢查下項目關聯的產品中有沒有需求,而且要確保它們已經審核通過。"; -$lang->project->doneProjects = '已結束'; -$lang->project->unDoneProjects = '未結束'; - -/* 交互提示。*/ -$lang->project->confirmDelete = '您確定刪除項目[%s]嗎?'; -$lang->project->confirmUnlinkMember = '您確定從該項目中移除該用戶嗎?'; -$lang->project->confirmUnlinkStory = '您確定從該項目中移除該需求嗎?'; -$lang->project->errorNoLinkedProducts = '該項目沒有關聯的產品,系統將轉到產品關聯頁面'; -$lang->project->accessDenied = '您無權訪問該項目!'; -$lang->project->tips = '提示'; -$lang->project->afterInfo = '項目添加成功,您現在可以進行以下操作:'; -$lang->project->setTeam = '設置團隊'; -$lang->project->linkStory = '關聯需求'; -$lang->project->createTask = '添加任務'; -$lang->project->goback = '返回項目首頁(5秒後將自動跳轉)'; - -/* 統計。*/ -$lang->project->charts->burn->graph->caption = "燃盡圖"; -$lang->project->charts->burn->graph->xAxisName = "日期"; -$lang->project->charts->burn->graph->yAxisName = "HOUR"; -$lang->project->charts->burn->graph->baseFontSize = 12; -$lang->project->charts->burn->graph->formatNumber = 0; -$lang->project->charts->burn->graph->animation = 0; -$lang->project->charts->burn->graph->rotateNames = 1; -$lang->project->charts->burn->graph->showValues = 0; + + * @package project + * @version $Id: zh-tw.php 2600 2012-02-21 04:35:05Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +/* 欄位列表。*/ +$lang->project->common = '項目視圖'; +$lang->project->id = '項目編號'; +$lang->project->company = '所屬公司'; +$lang->project->iscat = '作為目錄'; +$lang->project->type = '項目類型'; +$lang->project->parent = '上級項目'; +$lang->project->name = '項目名稱'; +$lang->project->code = '項目代號'; +$lang->project->begin = '開始日期'; +$lang->project->end = '結束日期'; +$lang->project->days = '可用工作日'; +$lang->project->status = '項目狀態'; +$lang->project->statge = '所處階段'; +$lang->project->pri = '優先順序'; +$lang->project->desc = '項目描述'; +$lang->project->goal = '項目目標'; +$lang->project->openedBy = '由誰創建'; +$lang->project->openedDate = '創建日期'; +$lang->project->closedBy = '由誰關閉'; +$lang->project->closedDate = '關閉日期'; +$lang->project->canceledBy = '由誰取消'; +$lang->project->canceledDate = '取消日期'; +$lang->project->PO = '產品負責人'; +$lang->project->PM = '項目負責人'; +$lang->project->QM = '測試負責人'; +$lang->project->RM = '發佈負責人'; +$lang->project->acl = '訪問控制'; +$lang->project->teamname = '團隊名稱'; +$lang->project->order = '項目排序'; +$lang->project->products = '相關產品'; +$lang->project->childProjects = '子項目'; +$lang->project->whitelist = '分組白名單'; +$lang->project->totalEstimate = '總預計'; +$lang->project->totalConsumed = '總消耗'; +$lang->project->totalLeft = '總剩餘'; +$lang->project->progess = '進度'; +$lang->project->viewBug = '查看bug'; +$lang->project->testtaskBrowse= '待測列表'; +$lang->project->createTesttask= '提交測試'; +$lang->project->noProduct = '無產品項目'; +$lang->project->select = '--請選擇項目--'; + +$lang->team->account = '用戶'; +$lang->team->role = '角色'; +$lang->team->join = '加盟日'; +$lang->team->hours = '可用工時/天'; +$lang->team->days = '可用工日'; +$lang->team->totalHours = '總計'; + +/* 欄位取值列表。*/ +$lang->project->statusList[''] = ''; +$lang->project->statusList['wait'] = '未開始'; +$lang->project->statusList['doing'] = '進行中'; +$lang->project->statusList['done'] = '已完成'; + +$lang->project->aclList['open'] = '預設設置(有項目視圖權限,即可訪問)'; +$lang->project->aclList['private'] = '私有項目(只有項目團隊成員才能訪問)'; +$lang->project->aclList['custom'] = '自定義白名單(團隊成員和白名單的成員可以訪問)'; + +/* 方法列表。*/ +$lang->project->index = "項目首頁"; +$lang->project->task = '任務列表'; +$lang->project->groupTask = '分組瀏覽任務'; +$lang->project->story = '需求列表'; +$lang->project->bug = 'Bug列表'; +$lang->project->dynamic = '動態'; +$lang->project->build = 'Build列表'; +$lang->project->testtask = '測試申請'; +$lang->project->burn = '燃盡圖'; +$lang->project->computeBurn = '更新燃盡圖'; +$lang->project->burnData = '燃盡圖數據'; +$lang->project->team = '團隊成員'; +$lang->project->doc = '文檔列表'; +$lang->project->manageProducts = '關聯產品'; +$lang->project->linkStory = '關聯需求'; +$lang->project->view = "基本信息"; +$lang->project->create = "添加項目"; +$lang->project->delete = "刪除項目"; +$lang->project->browse = "瀏覽項目"; +$lang->project->edit = "編輯項目"; +$lang->project->manageMembers = '團隊管理'; +$lang->project->unlinkMember = '移除成員'; +$lang->project->unlinkStory = '移除需求'; +$lang->project->importTask = '導入任務'; +$lang->project->importBug = '導入Bug'; +$lang->project->ajaxGetProducts = '介面:獲得項目產品列表'; + +/* 分組瀏覽。*/ +$lang->project->allTasks = '所有任務'; +$lang->project->assignedToMe = '指派給我'; +$lang->project->finishedByMe = '由我完成'; +$lang->project->statusWait = '未開始'; +$lang->project->statusDoing = '進行中'; +$lang->project->statusUndone = '未完成'; +$lang->project->statusDone = '已完成'; +$lang->project->statusClosed = '已關閉'; +$lang->project->delayed = '已延期'; +$lang->project->groups[''] = '分組查看'; +$lang->project->groups['story'] = '需求分組'; +$lang->project->groups['status'] = '狀態分組'; +$lang->project->groups['pri'] = '優先順序分組'; +$lang->project->groups['openedby'] = '創建者分組'; +$lang->project->groups['assignedTo'] = '指派給分組'; +$lang->project->groups['finishedby'] = '完成者分組'; +$lang->project->groups['closedby'] = '關閉者分組'; +$lang->project->groups['estimate'] = '預計分組'; +$lang->project->groups['consumed'] = '已消耗分組'; +$lang->project->groups['left'] = '剩餘分組'; +$lang->project->groups['type'] = '類型分組'; +$lang->project->groups['deadline'] = '截止分組'; +$lang->project->listTaskNeedConfrim = '需求變動'; +$lang->project->byQuery = '搜索'; + +/* 查詢條件列表。*/ +$lang->project->allProject = '所有項目'; +$lang->project->aboveAllProduct = '以上所有產品'; +$lang->project->aboveAllProject = '以上所有項目'; + +/* 頁面提示。*/ +$lang->project->selectProject = "請選擇項目"; +$lang->project->beginAndEnd = '起止時間'; +$lang->project->lblStats = '工時統計'; +$lang->project->stats = '可用工時%s工時
          總共預計%s工時
          已經消耗%s工時
          預計剩餘%s工時'; +$lang->project->oneLineStats = "項目%s, 代號為%s, 相關產品為%s%s開始,%s結束,總預計%s工時,已消耗%s工時,預計剩餘%s工時。"; +$lang->project->taskSummary = "本頁共 %s 個任務,未開始%s,進行中%s,總預計%s工時,已消耗%s工時,剩餘%s工時。"; +$lang->project->memberHours = "%s共有 %s 個可用工時,"; +$lang->project->groupSummary = "本組共 %s 個任務,未開始%s,進行中%s,總預計%s工時,已消耗%s工時,剩餘%s工時。"; +$lang->project->wbs = "分解任務"; +$lang->project->largeBurnChart = '點擊查看大圖'; +$lang->project->howToUpdateBurn = "如何更新?"; +$lang->project->whyNoStories = "看起來沒有需求可以關聯。請檢查下項目關聯的產品中有沒有需求,而且要確保它們已經審核通過。"; +$lang->project->doneProjects = '已結束'; +$lang->project->unDoneProjects = '未結束'; + +/* 交互提示。*/ +$lang->project->confirmDelete = '您確定刪除項目[%s]嗎?'; +$lang->project->confirmUnlinkMember = '您確定從該項目中移除該用戶嗎?'; +$lang->project->confirmUnlinkStory = '您確定從該項目中移除該需求嗎?'; +$lang->project->errorNoLinkedProducts = '該項目沒有關聯的產品,系統將轉到產品關聯頁面'; +$lang->project->accessDenied = '您無權訪問該項目!'; +$lang->project->tips = '提示'; +$lang->project->afterInfo = '項目添加成功,您現在可以進行以下操作:'; +$lang->project->setTeam = '設置團隊'; +$lang->project->linkStory = '關聯需求'; +$lang->project->createTask = '添加任務'; +$lang->project->goback = '返回項目首頁(5秒後將自動跳轉)'; + +/* 統計。*/ +$lang->project->charts->burn->graph->caption = "燃盡圖"; +$lang->project->charts->burn->graph->xAxisName = "日期"; +$lang->project->charts->burn->graph->yAxisName = "HOUR"; +$lang->project->charts->burn->graph->baseFontSize = 12; +$lang->project->charts->burn->graph->formatNumber = 0; +$lang->project->charts->burn->graph->animation = 0; +$lang->project->charts->burn->graph->rotateNames = 1; +$lang->project->charts->burn->graph->showValues = 0; diff --git a/module/project/model.php b/module/project/model.php index e123a975cd..0deadc5675 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -1,1065 +1,1065 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> -app->user->account . ','; - if(strpos($this->app->company->admins, $account) !== false) return true; - - /* If project is open, return true. */ - if($project->acl == 'open') return true; - - /* Get team members. */ - $teamMembers = $this->getTeamMemberPairs($project->id); - - /* If project is private, only members can access. */ - if($project->acl == 'private') - { - return isset($teamMembers[$this->app->user->account]); - } - - /* Project's acl is custom, check the groups. */ - if($project->acl == 'custom') - { - if(isset($teamMembers[$this->app->user->account])) return true; - $userGroups = $this->loadModel('user')->getGroups($this->app->user->account); - $projectGroups = explode(',', $project->whitelist); - foreach($userGroups as $groupID) - { - if(in_array($groupID, $projectGroups)) return true; - } - return false; - } - } - - /** - * Set menu. - * - * @param array $projects - * @param int $projectID - * @access public - * @return void - */ - public function setMenu($projects, $projectID) - { - /* Check the privilege. */ - if($projects and !isset($projects[$projectID]) and !$this->checkPriv($this->getById($projectID))) - { - echo(js::alert($this->lang->project->accessDenied)); - die(js::locate('back')); - } - - $moduleName = $this->app->getModuleName(); - $methodName = $this->app->getMethodName(); - $selectHtml = $this->select($projects, $projectID, $moduleName, $methodName); - foreach($this->lang->project->menu as $key => $menu) - { - $replace = $key == 'list' ? $selectHtml . $this->lang->arrow : $projectID; - common::setMenuVars($this->lang->project->menu, $key, $replace); - } - } - - /** - * Create the select code of projects. - * - * @param array $projects - * @param int $projectID - * @param string $currentModule - * @param string $currentMethod - * @access public - * @return string - */ - public function select($projects, $projectID, $currentModule, $currentMethod) - { - /* See product's model method:select. */ - $switchCode = "switchProject($('#projectID').val(), '$currentModule', '$currentMethod');"; - $onchange = "onchange=\"$switchCode\""; - $onkeypress = "onkeypress=\"eventKeyCode=event.keyCode; if(eventKeyCode == 13) $switchCode\""; - $onclick = "onclick=\"eventKeyCode = 13; $switchCode\""; - $selectHtml = html::select('projectID', $projects, $projectID, "tabindex=2 $onchange $onkeypress"); - $selectHtml .= html::commonButton($this->lang->go, "id='projectSwitcher' tabindex=3 $onclick"); - return $selectHtml; - } - - /** - * Save the project id user last visited to session. - * - * @param int $projectID - * @param array $projects - * @access public - * @return int - */ - public function saveState($projectID, $projects) - { - if($projectID > 0) $this->session->set('project', (int)$projectID); - if($projectID == 0 and $this->cookie->lastProject) $this->session->set('project', (int)$this->cookie->lastProject); - if($projectID == 0 and $this->session->project == '') $this->session->set('project', $projects[0]); - if(!in_array($this->session->project, $projects)) $this->session->set('project', $projects[0]); - return $this->session->project; - } - - /** - * Save order - * - * @access public - * @return void - */ - public function saveOrder() - { - foreach($_POST as $projectID => $order) - { - $this->dao->update(TABLE_PROJECT)->set('`order`')->eq($order)->where('id')->eq($projectID)->exec(); - } - } - - /** - * Create a project. - * - * @access public - * @return void - */ - public function create($copyProjectID = '') - { - $this->lang->project->team = $this->lang->project->teamname; - $project = fixer::input('post') - ->stripTags('name, code, team') - ->setIF($this->post->acl != 'custom', 'whitelist', '') - ->join('whitelist', ',') - ->remove('products') - ->get(); - $this->dao->insert(TABLE_PROJECT)->data($project) - ->autoCheck($skipFields = 'begin,end') - ->batchcheck($this->config->project->create->requiredFields, 'notempty') - ->checkIF($project->begin != '', 'begin', 'date') - ->checkIF($project->end != '', 'end', 'date') - ->checkIF($project->end != '', 'end', 'gt', $project->begin) - ->check('name', 'unique') - ->check('code', 'unique') - ->exec(); - - /* Add the creater to the team. */ - if(!dao::isError()) - { - $projectID = $this->dao->lastInsertId(); - $today = helper::today(); - - if($copyProjectID == '') - { - $member->project = $projectID; - $member->account = $this->app->user->account; - $member->join = $today; - $member->days = $project->days; - $member->hours = $this->config->project->defaultWorkhours; - $this->dao->insert(TABLE_TEAM)->data($member)->exec(); - } - else - { - $members = $this->dao->select('*')->from(TABLE_TEAM)->where('project')->eq($copyProjectID)->fetchAll(); - foreach($members as $member) - { - unset($member->company); - $member->project = $projectID; - $member->join = $today; - $this->dao->insert(TABLE_TEAM)->data($member)->exec(); - } - } - - return $projectID; - } - } - - /** - * Update a project. - * - * @param int $projectID - * @access public - * @return array - */ - public function update($projectID) - { - $oldProject = $this->getById($projectID); - $team = $this->getTeamMemberPairs($projectID); - $this->lang->project->team = $this->lang->project->teamname; - $projectID = (int)$projectID; - $project = fixer::input('post') - ->stripTags('name, code, team') - ->setIF($this->post->begin == '0000-00-00', 'begin', '') - ->setIF($this->post->end == '0000-00-00', 'end', '') - ->setIF($this->post->acl != 'custom', 'whitelist', '') - ->join('whitelist', ',') - ->remove('products') - ->get(); - $this->dao->update(TABLE_PROJECT)->data($project) - ->autoCheck($skipFields = 'begin,end') - ->batchcheck($this->config->project->edit->requiredFields, 'notempty') - ->checkIF($project->begin != '', 'begin', 'date') - ->checkIF($project->end != '', 'end', 'date') - ->checkIF($project->end != '', 'end', 'gt', $project->begin) - ->check('name', 'unique', "id!=$projectID") - ->check('code', 'unique', "id!=$projectID") - ->where('id')->eq($projectID) - ->limit(1) - ->exec(); - foreach($project as $fieldName => $value) - { - if($fieldName == 'PO' or $fieldName == 'PM' or $fieldName == 'QM' or $fieldName == 'RM' ) - { - if(!empty($value) and !isset($team[$value])) - { - $member->project = (int)$projectID; - $member->account = $value; - $member->join = helper::today(); - $member->role = $fieldName; - $member->days = $project->days; - $member->hours = $this->config->project->defaultWorkhours; - $this->dao->insert(TABLE_TEAM)->data($member)->exec(); - } - } - } - if(!dao::isError()) return common::createChanges($oldProject, $project); - } - - /** - * Get project pairs. - * - * @param string $mode all|noclosed or empty - * @access public - * @return array - */ - public function getPairs($mode = '') - { - $orderBy = !empty($this->config->project->orderBy) ? $this->config->project->orderBy : 'isDone, `order`, status'; - $mode .= $this->cookie->projectMode; - /* Order by status's content whether or not done */ - $projects = $this->dao->select('*, IF(INSTR(" done", status) < 2, 0, 1) AS isDone')->from(TABLE_PROJECT) - ->where('iscat')->eq(0) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy) - ->fetchAll(); - $pairs = array(); - foreach($projects as $project) - { - if(strpos($mode, 'noclosed') !== false and $project->status == 'done') continue; - if($this->checkPriv($project)) - { - if(strpos($mode, 'nocode') === false and $project->code) - { - $firstChar = strtoupper(substr($project->code, 0, 1)); - if(ord($firstChar) < 127) $project->name = $firstChar . ':' . $project->name; - } - $pairs[$project->id] = $project->name; - } - } - - /* If the pairs is empty, to make sure there's an project in the pairs. */ - if(empty($pairs) and isset($projects[0]) and $this->checkPriv($projects[0])) - { - $firstProject = $projects[0]; - $pairs[$firstProject->id] = $firstProject->name; - } - return $pairs; - } - - /** - * Get project lists. - * - * @param string $status all|undone|wait|running - * @param int $limit - * @access public - * @return array - */ - public function getList($status = 'all', $limit = 0, $productID = 0) - { - if($productID != 0) - { - return $this->dao->select('t2.*') - ->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2') - ->on('t1.project = t2.id') - ->where('t1.product')->eq($productID) - ->andWhere('t2.deleted')->eq(0) - ->andWhere('t2.iscat')->eq(0) - ->beginIF($status == 'undone')->andWhere('t2.status')->ne('done')->fi() - ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() - ->orderBy($this->config->project->orderBy) - ->beginIF($limit)->limit($limit)->fi() - ->fetchAll('id'); - } - else - { - return $this->dao->select('*, IF(INSTR(" done", status) < 2, 0, 1) AS isDone')->from(TABLE_PROJECT)->where('iscat')->eq(0) - ->beginIF($status == 'undone')->andWhere('status')->ne('done')->fi() - ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($this->config->project->orderBy) - ->beginIF($limit)->limit($limit)->fi() - ->fetchAll('id'); - } - } - - /** - * Get projects lists grouped by product. - * - * @access public - * @return array - */ - public function getProductGroupList() - { - $list = $this->dao->select('t1.id, t1.name, t2.product')->from(TABLE_PROJECT)->alias('t1') - ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.project') - ->where('t1.deleted')->eq(0) - ->orderBy('t1.id') - ->fetchGroup('product'); - - foreach($list as $id => $product) - { - foreach($product as $ID => $project) - { - if(!$this->checkPriv($this->getById($project->id))) - { - unset($list[$id][$ID]); - } - } - } - - return $list; - } - - /** - * Get project stats. - * - * @param string $status - * @access public - * @return array - */ - public function getProjectStats($status = 'undone', $productID = 0) - { - $this->loadModel('report'); - - $projects = $this->getList($status, 0, $productID); - $stats = array(); - - /* Get total estimate, consumed and left hours of project. */ - $emptyHour = (object)array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0); - $hours = $this->dao->select('project, SUM(estimate) AS totalEstimate, SUM(consumed) AS totalConsumed') - ->from(TABLE_TASK) - ->where('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->groupBy('project') - ->fetchAll('project'); - - $lefts = $this->dao->select('project, SUM(`left`) AS totalLeft') - ->from(TABLE_TASK) - ->where('project')->in(array_keys($projects)) - ->andWhere('closedReason')->ne('cancel') - ->andWhere('status')->ne('cancel') - ->andWhere('deleted')->eq(0) - ->groupBy('project') - ->fetchAll('project'); - foreach($lefts as $projectID => $projectLefts) $hours[$projectID]->totalLeft = $projectLefts->totalLeft; - - /* Round them. */ - foreach($hours as $hour) - { - $hour->totalEstimate = round($hour->totalEstimate, 1); - $hour->totalConsumed = round($hour->totalConsumed, 1); - $hour->totalLeft = round($hour->totalLeft, 1); - $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; - $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0; - } - - /* Get tasks stats group by status. */ - $tasks = $this->dao->select('project, status, count(status) AS count') - ->from(TABLE_TASK) - ->where('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq(0) - ->groupBy('project, status') - ->fetchGroup('project', 'status'); - - /* Process projects. */ - foreach($projects as $key => $project) - { - if($this->checkPriv($project)) - { - // Process the end time. - $project->end = date(DT_DATE4, strtotime($project->end)); - - /* Process the burns. */ - $project->burns = array(); - $burnData = $this->getBurnData($project->id); - foreach($burnData as $data) $project->burns[] = $data->value; - $stats[] = $project; - - /* Process the hours. */ - $project->hours = isset($hours[$project->id]) ? $hours[$project->id] : $emptyHour; - - /* Process the tasks. */ - $project->tasks = isset($tasks[$project->id]) ? $tasks[$project->id] : array(); - } - else - { - unset($projects[$key]); - } - } - - return $stats; - } - - /** - * Get project by id. - * - * @param int $projectID - * @access public - * @return void - */ - public function getById($projectID) - { - $project = $this->dao->findById((int)$projectID)->from(TABLE_PROJECT)->fetch(); - if(!$project) return false; - $total = $this->dao->select(' - SUM(estimate) AS totalEstimate, - SUM(consumed) AS totalConsumed, - SUM(`left`) AS totalLeft') - ->from(TABLE_TASK) - ->where('project')->eq((int)$projectID) - ->andWhere('status')->ne('cancel') - ->andWhere('deleted')->eq(0) - ->fetch(); - $project->days = $project->days ? $project->days : ''; - $project->totalHours = $this->dao->select('sum(days * hours) AS totalHours')->from(TABLE_TEAM)->where('project')->eq($project->id)->fetch('totalHours'); - $project->totalEstimate = round($total->totalEstimate, 1); - $project->totalConsumed = round($total->totalConsumed, 1); - $project->totalLeft = round($total->totalLeft, 1); - $project->desc = $this->loadModel('file')->setImgSize($project->desc); - $project->goal = $this->loadModel('file')->setImgSize($project->goal); - return $project; - } - - /** - * Get the default managers for a project from it's related products. - * - * @param int $projectID - * @access public - * @return object - */ - public function getDefaultManagers($projectID) - { - $managers = $this->dao->select('PO,QM,RM')->from(TABLE_PRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.product') - ->where('t2.project')->eq($projectID) - ->fetch(); - if($managers) return $managers; - - $managers->PO = ''; - $managers->QM = ''; - $managers->RM = ''; - return $managers; - } - - /** - * Get products of a project. - * - * @param int $projectID - * @access public - * @return array - */ - public function getProducts($projectID) - { - return $this->dao->select('t2.id, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product = t2.id') - ->where('t1.project')->eq((int)$projectID) - ->fetchPairs(); - } - - /** - * Update products of a project. - * - * @param int $projectID - * @access public - * @return void - */ - public function updateProducts($projectID) - { - $this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->exec(); - if(!isset($_POST['products'])) return; - $products = array_unique($_POST['products']); - foreach($products as $productID) - { - $data->project = $projectID; - $data->product = $productID; - $this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec(); - } - } - - /** - * Get related projects - * - * @param int $projectID - * @access public - * @return array - */ - public function getRelatedProjects($projectID) - { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->fetchAll('product'); - if(!$products) return array(); - $products = array_keys($products); - return $this->dao->select('t1.id, t1.name')->from(TABLE_PROJECT)->alias('t1') - ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2') - ->on('t1.id = t2.project') - ->where('t2.product')->in($products) - ->andWhere('t1.id')->ne((int)$projectID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy('t1.id') - ->fetchPairs(); - } - - /** - * Get rasks can be imported. - * - * @param int $projectID - * @access public - * @return array - */ - public function getTasks2Imported($projectID) - { - $this->loadModel('task'); - $releatedProjects = $this->getRelatedProjects($projectID); - if(!$releatedProjects) return array(); - $tasks = array(); - foreach($releatedProjects as $releatedProjectID => $releatedProjectName) - { - $projectTasks = $this->task->getProjectTasks($releatedProjectID, 'wait,doing,cancel'); - if(!$projectTasks) continue; - $tasks = array_merge($tasks, $projectTasks); - } - return $tasks; - } - - /** - * Import tasks. - * - * @param int $projectID - * @access public - * @return void - */ - public function importTask($projectID) - { - $this->loadModel('task'); - - /* Update tasks. */ - $tasks = $this->dao->select('id, project, assignedTo, story, consumed,status')->from(TABLE_TASK)->where('id')->in($this->post->tasks)->fetchAll('id'); - foreach($tasks as $task) - { - /* Save the assignedToes and stories, should linked to project. */ - $assignedToes[$task->assignedTo] = $task->project; - $stories[$task->story] = $task->story; - - $data = new stdclass(); - $data->project = $projectID; - - if($task->status == 'cancel') - { - $data->canceledBy = ''; - $data->canceledDate = NULL; - } - - $data->status = $task->consumed > 0 ? 'doing' : 'wait'; - $data->statusCustom = strpos(TASKMODEL::CUSTOM_STATUS_ORDER, $data->status) + 1; - $this->dao->update(TABLE_TASK)->data($data)->where('id')->in($this->post->tasks)->exec(); - $this->loadModel('action')->create('task', $task->id, 'moved', '', $task->project); - } - - /* Remove empty story. */ - unset($stories[0]); - - /* Add members to project team. */ - $teamMembers = $this->getTeamMemberPairs($projectID); - foreach($assignedToes as $account => $preProjectID) - { - if(!isset($teamMembers[$account])) - { - $role = $this->dao->select('*')->from(TABLE_TEAM)->where('project')->eq($preProjectID)->andWhere('account')->eq($account)->fetch(); - $role->project = $projectID; - $role->join = helper::today(); - $this->dao->insert(TABLE_TEAM)->data($role)->exec(); - } - } - - /* Link stories. */ - $projectStories = $this->loadModel('story')->getProjectStoryPairs($projectID); - foreach($stories as $storyID) - { - if(!isset($projectStories[$storyID])) - { - $story = $this->dao->findById($storyID)->fields("$projectID as project, id as story, product, version")->from(TABLE_STORY)->fetch(); - $this->dao->insert(TABLE_PROJECTSTORY)->data($story)->exec(); - } - } - } - - /** - * Import task from Bug. - * - * @param int $projectID - * @access public - * @return void - */ - public function importBug($projectID) - { - $this->loadModel('bug'); - $bugLang = $this->app->loadLang('bug'); - $this->loadModel('task'); - $this->loadModel('story'); - - $now = helper::now(); - $BugToTasks = fixer::input('post')->get(); - foreach($BugToTasks->import as $key => $value) - { - $bug = $this->bug->getById($key); - $task->project = $projectID; - $task->story = $bug->story; - $task->storyVersion = $bug->story; - $task->fromBug = $key; - $task->name = $bug->title; - $task->type = 'devel'; - $task->pri = $BugToTasks->pri[$key]; - $task->consumed = 0; - $task->status = 'wait'; - $task->statusCustom = strpos(taskModel::CUSTOM_STATUS_ORDER, 'wait') + 1; - $task->desc = $bugLang->bug->resolve . ':' . '#' . html::a(helper::createLink('bug', 'view', "bugID=$key"), sprintf('%03d', $key)); - $task->openedDate = $now; - $task->openedBy = $this->app->user->account; - if(!empty($BugToTasks->estimate[$key])) - { - $task->estimate = $BugToTasks->estimate[$key]; - $task->left = $task->estimate; - } - if(!empty($BugToTasks->assignedTo[$key])) - { - $task->assignedTo = $BugToTasks->assignedTo[$key]; - $task->assignedDate = $now; - } - $this->dao->insert(TABLE_TASK)->data($task)->checkIF($BugToTasks->estimate[$key] != '', 'estimate', 'float')->exec(); - - if(dao::isError()) - { - echo js::error(dao::getError()); - die(js::reload('parent')); - } - - $taskID = $this->dao->lastInsertID(); - if($task->story != false) $this->story->setStage($task->story); - $actionID = $this->loadModel('action')->create('task', $taskID, 'Opened', ''); - $this->action->create('bug', $key, 'Totask', '', $taskID); - $this->dao->update(TABLE_BUG)->set('toTask')->eq($taskID)->where('id')->eq($key)->exec(); - $mails[$key]->taskID = $taskID; - $mails[$key]->actionID = $actionID; - } - return $mails; - } - - /** - * Get child projects. - * - * @param int $projectID - * @access public - * @return void - */ - public function getChildProjects($projectID) - { - return $this->dao->select('id, name')->from(TABLE_PROJECT)->where('parent')->eq((int)$projectID)->fetchPairs(); - } - - /** - * Update childs. - * - * @param int $projectID - * @access public - * @return void - */ - public function updateChilds($projectID) - { - $sql = "UPDATE " . TABLE_PROJECT . " SET parent = 0 WHERE parent = '$projectID'"; - $this->dbh->exec($sql); - if(!isset($_POST['childs'])) return; - $childs = array_unique($_POST['childs']); - foreach($childs as $childProjectID) - { - $sql = "UPDATE " . TABLE_PROJECT . " SET parent = '$projectID' WHERE id = '$childProjectID'"; - $this->dbh->query($sql); - } - } - - /** - * Link story. - * - * @param int $projectID - * @access public - * @return void - */ - public function linkStory($projectID) - { - if($this->post->stories == false) return false; - $this->loadModel('action'); - $versions = $this->loadModel('story')->getVersions($this->post->stories); - foreach($this->post->stories as $key => $storyID) - { - $productID = $this->post->products[$key]; - $data->project = $projectID; - $data->product = $productID; - $data->story = $storyID; - $data->version = $versions[$storyID]; - $this->dao->insert(TABLE_PROJECTSTORY)->data($data)->exec(); - $this->story->setStage($storyID); - $this->action->create('story', $storyID, 'linked2project', '', $projectID); - } - } - - /** - * Unlink story. - * - * @param int $projectID - * @param int $storyID - * @access public - * @return void - */ - public function unlinkStory($projectID, $storyID) - { - $this->dao->delete()->from(TABLE_PROJECTSTORY)->where('project')->eq($projectID)->andWhere('story')->eq($storyID)->limit(1)->exec(); - $this->loadModel('story')->setStage($storyID); - $this->loadModel('action')->create('story', $storyID, 'unlinkedfromproject', '', $projectID); - $tasks = $this->dao->select('id')->from(TABLE_TASK)->where('story')->eq($storyID)->andWhere('project')->eq($projectID)->andWhere('status')->in('wait,doing')->fetchPairs('id'); - $this->dao->update(TABLE_TASK)->set('status')->eq('cancel')->where('id')->in($tasks)->exec(); - foreach($tasks as $taskID) - { - $changes = $this->loadModel('task')->cancel($taskID); - $actionID = $this->action->create('task', $taskID, 'Canceled'); - $this->action->logHistory($actionID, $changes); - } - } - - /** - * Get team members. - * - * @param int $projectID - * @access public - * @return array - */ - public function getTeamMembers($projectID) - { - return $this->dao->select('t1.*, t1.hours * t1.days AS totalHours, t2.realname')->from(TABLE_TEAM)->alias('t1') - ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') - ->where('t1.project')->eq((int)$projectID) - ->andWHere('t2.company')->eq($this->app->company->id) - ->fetchAll('account'); - } - - /** - * Get team members in pair. - * - * @param int $projectID - * @param string $params - * @access public - * @return array - */ - public function getTeamMemberPairs($projectID, $params = '') - { - $users = $this->dao->select('t1.account, t2.realname')->from(TABLE_TEAM)->alias('t1') - ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') - ->where('t1.project')->eq((int)$projectID) - ->andWHere('t2.company')->eq($this->app->company->id) - ->beginIF($params == 'nodeleted') - ->andWhere('t2.deleted')->eq(0) - ->fi() - ->fetchPairs(); - if(!$users) return array(); - foreach($users as $account => $realName) - { - $firstLetter = ucfirst(substr($account, 0, 1)) . ':'; - $users[$account] = $firstLetter . ($realName ? $realName : $account); - } - return array('' => '') + $users; - } - - /** - * Manage team members. - * - * @param int $projectID - * @access public - * @return void - */ - public function manageMembers($projectID) - { - extract($_POST); - - $accounts = array_unique($accounts); - foreach($accounts as $key => $account) - { - if(empty($account)) continue; - - $member->role = $roles[$key]; - $member->days = $days[$key]; - $member->hours = $hours[$key]; - $mode = $modes[$key]; - - if($mode == 'update') - { - $this->dao->update(TABLE_TEAM)->data($member)->where('project')->eq((int)$projectID)->andWhere('account')->eq($account)->exec(); - } - else - { - $member->project = (int)$projectID; - $member->account = $account; - $member->join = helper::today(); - $this->dao->insert(TABLE_TEAM)->data($member)->exec(); - } - } - } - - /** - * Unlink a member. - * - * @param int $projectID - * @param string $account - * @access public - * @return void - */ - public function unlinkMember($projectID, $account) - { - $this->dao->delete()->from(TABLE_TEAM)->where('project')->eq((int)$projectID)->andWhere('account')->eq($account)->exec(); - } - - /** - * Compute burn of a project. - * - * @access public - * @return array - */ - public function computeBurn() - { - $today = helper::today(); - $burns = array(); - - $projects = $this->dao->select('id, name')->from(TABLE_PROJECT) - ->where("end >= '$today'") - ->orWhere('end')->eq('0000-00-00') - ->fetchPairs(); - if(!$projects) return $burns; - - $burns = $this->dao->select("project, '$today' AS date, sum(`left`) AS `left`, SUM(consumed) AS `consumed`") - ->from(TABLE_TASK) - ->where('project')->in(array_keys($projects)) - ->andWhere('deleted')->eq('0') - ->andWhere('status')->notin('cancel,closed') - ->groupBy('project') - ->fetchAll(); - - foreach($burns as $Key => $burn) - { - $this->dao->replace(TABLE_BURN)->data($burn)->exec(); - $burn->projectName = $projects[$burn->project]; - } - return $burns; - } - - /** - * Get data of burn down chart. - * - * @param int $projectID - * @param int $itemCounts - * @access public - * @return array - */ - public function getBurnData($projectID = 0, $itemCounts = 30) - { - /* Get project and burn counts. */ - $project = $this->getById($projectID); - $burnCounts = $this->dao->select('count(*) AS counts')->from(TABLE_BURN)->where('project')->eq($projectID)->fetch('counts'); - - /* If the burnCounts > $itemCounts, get the latest $itemCounts records. */ - $sql = $this->dao->select('date AS name, `left` AS value')->from(TABLE_BURN)->where('project')->eq((int)$projectID); - if($burnCounts > $itemCounts) - { - $sets = $sql->orderBy('date DESC')->limit($itemCounts)->fetchAll('name'); - $sets = array_reverse($sets); - } - else - { - /* The burnCounts < itemCounts, after getting from the db, padding left dates. */ - $sets = $sql->orderBy('date ASC')->fetchAll('name'); - $current = helper::today(); - if($project->end != '0000-00-00') - { - $period = helper::diffDate($project->end, $project->begin) + 1; - $counts = $period > $itemCounts ? $itemCounts : $period; - } - else - { - $counts = $itemCounts; - } - - for($i = 0; $i < $counts - $burnCounts; $i ++) - { - if(helper::diffDate($current, $project->end) > 0) break; - if(!isset($sets[$current])) - { - $sets[$current]->name = $current; - $sets[$current]->value = ''; - } - $nextDay = date(DT_DATE1, strtotime('next day', strtotime($current))); - $current = $nextDay; - } - } - foreach($sets as $set) $set->name = substr($set->name, 5); - return $sets; - } - - public function getBurnDataFlot($projectID = 0, $itemCounts = 30) - { - /* Get project and burn counts. */ - $project = $this->getById($projectID); - $burnCounts = $this->dao->select('count(*) AS counts')->from(TABLE_BURN)->where('project')->eq($projectID)->fetch('counts'); - - /* If the burnCounts > $itemCounts, get the latest $itemCounts records. */ - $sql = $this->dao->select('date AS name, `left` AS value')->from(TABLE_BURN)->where('project')->eq((int)$projectID); - if($burnCounts > $itemCounts) - { - $sets = $sql->orderBy('date DESC')->limit($itemCounts)->fetchAll('name'); - $sets = array_reverse($sets); - } - else - { - /* The burnCounts < itemCounts, after getting from the db, padding left dates. */ - $sets = $sql->orderBy('date ASC')->fetchAll('name'); - $current = helper::today(); - if($project->end != '0000-00-00') - { - $period = helper::diffDate($project->end, $project->begin) + 1; - $counts = $period > $itemCounts ? $itemCounts : $period; - } - else - { - $counts = $itemCounts; - } - - for($i = 0; $i < $counts - $burnCounts; $i ++) - { - if(helper::diffDate($current, $project->end) > 0) break; - if(!isset($sets[$current])) - { - $sets[$current]->name = $current; - $sets[$current]->value = ''; - } - $nextDay = date(DT_DATE1, strtotime('next day', strtotime($current))); - $current = $nextDay; - } - } - $count = 0; - foreach($sets as $set) - { - $set->name = (string)strtotime("$set->name UTC") . '000'; - $count ++; - } - $sets['count'] = $count; - return $sets; - } - - /** - * Get taskes by search. - * - * @param string $condition - * @param object $pager - * @param string $orderBy - * @access public - * @return array - */ - public function getSearchTasks($condition, $pager, $orderBy) - { - $taskIdList = $this->dao->select('id') - ->from(TABLE_TASK) - ->where($condition) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll('id'); - - $tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') - ->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') - ->leftJoin(TABLE_USER)->alias('t3')->on('t1.assignedTo = t3.account') - ->where('t1.deleted')->eq(0) - ->andWhere('t1.id')->in(array_keys($taskIdList)) - ->orderBy($orderBy) - ->fetchAll(); - return $tasks; - } - - /** - * Get bugs by search in project. - * - * @param int $products - * @param int $projectID - * @param int $sql - * @param int $pager - * @param int $orderBy - * @access public - * @return void - */ - public function getSearchBugs($products, $projectID, $sql, $pager, $orderBy) - { - return $this->dao->select('*')->from(TABLE_BUG) - ->where($sql) - ->andWhere('status')->eq('active') - ->andWhere('toTask')->eq(0) - ->andWhere('tostory')->eq(0) - ->beginIF(!empty($products))->andWhere('product')->in(array_keys($products))->fi() - ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - } - - /** - * Get resolved bugs of a project - * - * @param int $projectID - * @access public - * @return array - */ - public function getResolvedBugs($projectID) - { - $project = $this->getById($projectID); - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); - return $this->dao->select('id, title, status')->from(TABLE_BUG) - ->where('status')->eq('resolved') - ->andWhere('resolvedDate')->ge($project->begin) - ->andWhere('resolution')->eq('fixed') - ->andWhere('product')->in($products) - ->fetchAll(); - } -} + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> +app->user->account . ','; + if(strpos($this->app->company->admins, $account) !== false) return true; + + /* If project is open, return true. */ + if($project->acl == 'open') return true; + + /* Get team members. */ + $teamMembers = $this->getTeamMemberPairs($project->id); + + /* If project is private, only members can access. */ + if($project->acl == 'private') + { + return isset($teamMembers[$this->app->user->account]); + } + + /* Project's acl is custom, check the groups. */ + if($project->acl == 'custom') + { + if(isset($teamMembers[$this->app->user->account])) return true; + $userGroups = $this->loadModel('user')->getGroups($this->app->user->account); + $projectGroups = explode(',', $project->whitelist); + foreach($userGroups as $groupID) + { + if(in_array($groupID, $projectGroups)) return true; + } + return false; + } + } + + /** + * Set menu. + * + * @param array $projects + * @param int $projectID + * @access public + * @return void + */ + public function setMenu($projects, $projectID) + { + /* Check the privilege. */ + if($projects and !isset($projects[$projectID]) and !$this->checkPriv($this->getById($projectID))) + { + echo(js::alert($this->lang->project->accessDenied)); + die(js::locate('back')); + } + + $moduleName = $this->app->getModuleName(); + $methodName = $this->app->getMethodName(); + $selectHtml = $this->select($projects, $projectID, $moduleName, $methodName); + foreach($this->lang->project->menu as $key => $menu) + { + $replace = $key == 'list' ? $selectHtml . $this->lang->arrow : $projectID; + common::setMenuVars($this->lang->project->menu, $key, $replace); + } + } + + /** + * Create the select code of projects. + * + * @param array $projects + * @param int $projectID + * @param string $currentModule + * @param string $currentMethod + * @access public + * @return string + */ + public function select($projects, $projectID, $currentModule, $currentMethod) + { + /* See product's model method:select. */ + $switchCode = "switchProject($('#projectID').val(), '$currentModule', '$currentMethod');"; + $onchange = "onchange=\"$switchCode\""; + $onkeypress = "onkeypress=\"eventKeyCode=event.keyCode; if(eventKeyCode == 13) $switchCode\""; + $onclick = "onclick=\"eventKeyCode = 13; $switchCode\""; + $selectHtml = html::select('projectID', $projects, $projectID, "tabindex=2 $onchange $onkeypress"); + $selectHtml .= html::commonButton($this->lang->go, "id='projectSwitcher' tabindex=3 $onclick"); + return $selectHtml; + } + + /** + * Save the project id user last visited to session. + * + * @param int $projectID + * @param array $projects + * @access public + * @return int + */ + public function saveState($projectID, $projects) + { + if($projectID > 0) $this->session->set('project', (int)$projectID); + if($projectID == 0 and $this->cookie->lastProject) $this->session->set('project', (int)$this->cookie->lastProject); + if($projectID == 0 and $this->session->project == '') $this->session->set('project', $projects[0]); + if(!in_array($this->session->project, $projects)) $this->session->set('project', $projects[0]); + return $this->session->project; + } + + /** + * Save order + * + * @access public + * @return void + */ + public function saveOrder() + { + foreach($_POST as $projectID => $order) + { + $this->dao->update(TABLE_PROJECT)->set('`order`')->eq($order)->where('id')->eq($projectID)->exec(); + } + } + + /** + * Create a project. + * + * @access public + * @return void + */ + public function create($copyProjectID = '') + { + $this->lang->project->team = $this->lang->project->teamname; + $project = fixer::input('post') + ->stripTags('name, code, team') + ->setIF($this->post->acl != 'custom', 'whitelist', '') + ->join('whitelist', ',') + ->remove('products') + ->get(); + $this->dao->insert(TABLE_PROJECT)->data($project) + ->autoCheck($skipFields = 'begin,end') + ->batchcheck($this->config->project->create->requiredFields, 'notempty') + ->checkIF($project->begin != '', 'begin', 'date') + ->checkIF($project->end != '', 'end', 'date') + ->checkIF($project->end != '', 'end', 'gt', $project->begin) + ->check('name', 'unique') + ->check('code', 'unique') + ->exec(); + + /* Add the creater to the team. */ + if(!dao::isError()) + { + $projectID = $this->dao->lastInsertId(); + $today = helper::today(); + + if($copyProjectID == '') + { + $member->project = $projectID; + $member->account = $this->app->user->account; + $member->join = $today; + $member->days = $project->days; + $member->hours = $this->config->project->defaultWorkhours; + $this->dao->insert(TABLE_TEAM)->data($member)->exec(); + } + else + { + $members = $this->dao->select('*')->from(TABLE_TEAM)->where('project')->eq($copyProjectID)->fetchAll(); + foreach($members as $member) + { + unset($member->company); + $member->project = $projectID; + $member->join = $today; + $this->dao->insert(TABLE_TEAM)->data($member)->exec(); + } + } + + return $projectID; + } + } + + /** + * Update a project. + * + * @param int $projectID + * @access public + * @return array + */ + public function update($projectID) + { + $oldProject = $this->getById($projectID); + $team = $this->getTeamMemberPairs($projectID); + $this->lang->project->team = $this->lang->project->teamname; + $projectID = (int)$projectID; + $project = fixer::input('post') + ->stripTags('name, code, team') + ->setIF($this->post->begin == '0000-00-00', 'begin', '') + ->setIF($this->post->end == '0000-00-00', 'end', '') + ->setIF($this->post->acl != 'custom', 'whitelist', '') + ->join('whitelist', ',') + ->remove('products') + ->get(); + $this->dao->update(TABLE_PROJECT)->data($project) + ->autoCheck($skipFields = 'begin,end') + ->batchcheck($this->config->project->edit->requiredFields, 'notempty') + ->checkIF($project->begin != '', 'begin', 'date') + ->checkIF($project->end != '', 'end', 'date') + ->checkIF($project->end != '', 'end', 'gt', $project->begin) + ->check('name', 'unique', "id!=$projectID") + ->check('code', 'unique', "id!=$projectID") + ->where('id')->eq($projectID) + ->limit(1) + ->exec(); + foreach($project as $fieldName => $value) + { + if($fieldName == 'PO' or $fieldName == 'PM' or $fieldName == 'QM' or $fieldName == 'RM' ) + { + if(!empty($value) and !isset($team[$value])) + { + $member->project = (int)$projectID; + $member->account = $value; + $member->join = helper::today(); + $member->role = $fieldName; + $member->days = $project->days; + $member->hours = $this->config->project->defaultWorkhours; + $this->dao->insert(TABLE_TEAM)->data($member)->exec(); + } + } + } + if(!dao::isError()) return common::createChanges($oldProject, $project); + } + + /** + * Get project pairs. + * + * @param string $mode all|noclosed or empty + * @access public + * @return array + */ + public function getPairs($mode = '') + { + $orderBy = !empty($this->config->project->orderBy) ? $this->config->project->orderBy : 'isDone, `order`, status'; + $mode .= $this->cookie->projectMode; + /* Order by status's content whether or not done */ + $projects = $this->dao->select('*, IF(INSTR(" done", status) < 2, 0, 1) AS isDone')->from(TABLE_PROJECT) + ->where('iscat')->eq(0) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy) + ->fetchAll(); + $pairs = array(); + foreach($projects as $project) + { + if(strpos($mode, 'noclosed') !== false and $project->status == 'done') continue; + if($this->checkPriv($project)) + { + if(strpos($mode, 'nocode') === false and $project->code) + { + $firstChar = strtoupper(substr($project->code, 0, 1)); + if(ord($firstChar) < 127) $project->name = $firstChar . ':' . $project->name; + } + $pairs[$project->id] = $project->name; + } + } + + /* If the pairs is empty, to make sure there's an project in the pairs. */ + if(empty($pairs) and isset($projects[0]) and $this->checkPriv($projects[0])) + { + $firstProject = $projects[0]; + $pairs[$firstProject->id] = $firstProject->name; + } + return $pairs; + } + + /** + * Get project lists. + * + * @param string $status all|undone|wait|running + * @param int $limit + * @access public + * @return array + */ + public function getList($status = 'all', $limit = 0, $productID = 0) + { + if($productID != 0) + { + return $this->dao->select('t2.*') + ->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2') + ->on('t1.project = t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t2.deleted')->eq(0) + ->andWhere('t2.iscat')->eq(0) + ->beginIF($status == 'undone')->andWhere('t2.status')->ne('done')->fi() + ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() + ->orderBy($this->config->project->orderBy) + ->beginIF($limit)->limit($limit)->fi() + ->fetchAll('id'); + } + else + { + return $this->dao->select('*, IF(INSTR(" done", status) < 2, 0, 1) AS isDone')->from(TABLE_PROJECT)->where('iscat')->eq(0) + ->beginIF($status == 'undone')->andWhere('status')->ne('done')->fi() + ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($this->config->project->orderBy) + ->beginIF($limit)->limit($limit)->fi() + ->fetchAll('id'); + } + } + + /** + * Get projects lists grouped by product. + * + * @access public + * @return array + */ + public function getProductGroupList() + { + $list = $this->dao->select('t1.id, t1.name, t2.product')->from(TABLE_PROJECT)->alias('t1') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.project') + ->where('t1.deleted')->eq(0) + ->orderBy('t1.id') + ->fetchGroup('product'); + + foreach($list as $id => $product) + { + foreach($product as $ID => $project) + { + if(!$this->checkPriv($this->getById($project->id))) + { + unset($list[$id][$ID]); + } + } + } + + return $list; + } + + /** + * Get project stats. + * + * @param string $status + * @access public + * @return array + */ + public function getProjectStats($status = 'undone', $productID = 0) + { + $this->loadModel('report'); + + $projects = $this->getList($status, 0, $productID); + $stats = array(); + + /* Get total estimate, consumed and left hours of project. */ + $emptyHour = (object)array('totalEstimate' => 0, 'totalConsumed' => 0, 'totalLeft' => 0, 'progress' => 0); + $hours = $this->dao->select('project, SUM(estimate) AS totalEstimate, SUM(consumed) AS totalConsumed') + ->from(TABLE_TASK) + ->where('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + + $lefts = $this->dao->select('project, SUM(`left`) AS totalLeft') + ->from(TABLE_TASK) + ->where('project')->in(array_keys($projects)) + ->andWhere('closedReason')->ne('cancel') + ->andWhere('status')->ne('cancel') + ->andWhere('deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + foreach($lefts as $projectID => $projectLefts) $hours[$projectID]->totalLeft = $projectLefts->totalLeft; + + /* Round them. */ + foreach($hours as $hour) + { + $hour->totalEstimate = round($hour->totalEstimate, 1); + $hour->totalConsumed = round($hour->totalConsumed, 1); + $hour->totalLeft = round($hour->totalLeft, 1); + $hour->totalReal = $hour->totalConsumed + $hour->totalLeft; + $hour->progress = $hour->totalReal ? round($hour->totalConsumed / $hour->totalReal, 3) * 100 : 0; + } + + /* Get tasks stats group by status. */ + $tasks = $this->dao->select('project, status, count(status) AS count') + ->from(TABLE_TASK) + ->where('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq(0) + ->groupBy('project, status') + ->fetchGroup('project', 'status'); + + /* Process projects. */ + foreach($projects as $key => $project) + { + if($this->checkPriv($project)) + { + // Process the end time. + $project->end = date(DT_DATE4, strtotime($project->end)); + + /* Process the burns. */ + $project->burns = array(); + $burnData = $this->getBurnData($project->id); + foreach($burnData as $data) $project->burns[] = $data->value; + $stats[] = $project; + + /* Process the hours. */ + $project->hours = isset($hours[$project->id]) ? $hours[$project->id] : $emptyHour; + + /* Process the tasks. */ + $project->tasks = isset($tasks[$project->id]) ? $tasks[$project->id] : array(); + } + else + { + unset($projects[$key]); + } + } + + return $stats; + } + + /** + * Get project by id. + * + * @param int $projectID + * @access public + * @return void + */ + public function getById($projectID) + { + $project = $this->dao->findById((int)$projectID)->from(TABLE_PROJECT)->fetch(); + if(!$project) return false; + $total = $this->dao->select(' + SUM(estimate) AS totalEstimate, + SUM(consumed) AS totalConsumed, + SUM(`left`) AS totalLeft') + ->from(TABLE_TASK) + ->where('project')->eq((int)$projectID) + ->andWhere('status')->ne('cancel') + ->andWhere('deleted')->eq(0) + ->fetch(); + $project->days = $project->days ? $project->days : ''; + $project->totalHours = $this->dao->select('sum(days * hours) AS totalHours')->from(TABLE_TEAM)->where('project')->eq($project->id)->fetch('totalHours'); + $project->totalEstimate = round($total->totalEstimate, 1); + $project->totalConsumed = round($total->totalConsumed, 1); + $project->totalLeft = round($total->totalLeft, 1); + $project->desc = $this->loadModel('file')->setImgSize($project->desc); + $project->goal = $this->loadModel('file')->setImgSize($project->goal); + return $project; + } + + /** + * Get the default managers for a project from it's related products. + * + * @param int $projectID + * @access public + * @return object + */ + public function getDefaultManagers($projectID) + { + $managers = $this->dao->select('PO,QM,RM')->from(TABLE_PRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id = t2.product') + ->where('t2.project')->eq($projectID) + ->fetch(); + if($managers) return $managers; + + $managers->PO = ''; + $managers->QM = ''; + $managers->RM = ''; + return $managers; + } + + /** + * Get products of a project. + * + * @param int $projectID + * @access public + * @return array + */ + public function getProducts($projectID) + { + return $this->dao->select('t2.id, t2.name')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product = t2.id') + ->where('t1.project')->eq((int)$projectID) + ->fetchPairs(); + } + + /** + * Update products of a project. + * + * @param int $projectID + * @access public + * @return void + */ + public function updateProducts($projectID) + { + $this->dao->delete()->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->exec(); + if(!isset($_POST['products'])) return; + $products = array_unique($_POST['products']); + foreach($products as $productID) + { + $data->project = $projectID; + $data->product = $productID; + $this->dao->insert(TABLE_PROJECTPRODUCT)->data($data)->exec(); + } + } + + /** + * Get related projects + * + * @param int $projectID + * @access public + * @return array + */ + public function getRelatedProjects($projectID) + { + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq((int)$projectID)->fetchAll('product'); + if(!$products) return array(); + $products = array_keys($products); + return $this->dao->select('t1.id, t1.name')->from(TABLE_PROJECT)->alias('t1') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2') + ->on('t1.id = t2.project') + ->where('t2.product')->in($products) + ->andWhere('t1.id')->ne((int)$projectID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('t1.id') + ->fetchPairs(); + } + + /** + * Get rasks can be imported. + * + * @param int $projectID + * @access public + * @return array + */ + public function getTasks2Imported($projectID) + { + $this->loadModel('task'); + $releatedProjects = $this->getRelatedProjects($projectID); + if(!$releatedProjects) return array(); + $tasks = array(); + foreach($releatedProjects as $releatedProjectID => $releatedProjectName) + { + $projectTasks = $this->task->getProjectTasks($releatedProjectID, 'wait,doing,cancel'); + if(!$projectTasks) continue; + $tasks = array_merge($tasks, $projectTasks); + } + return $tasks; + } + + /** + * Import tasks. + * + * @param int $projectID + * @access public + * @return void + */ + public function importTask($projectID) + { + $this->loadModel('task'); + + /* Update tasks. */ + $tasks = $this->dao->select('id, project, assignedTo, story, consumed,status')->from(TABLE_TASK)->where('id')->in($this->post->tasks)->fetchAll('id'); + foreach($tasks as $task) + { + /* Save the assignedToes and stories, should linked to project. */ + $assignedToes[$task->assignedTo] = $task->project; + $stories[$task->story] = $task->story; + + $data = new stdclass(); + $data->project = $projectID; + + if($task->status == 'cancel') + { + $data->canceledBy = ''; + $data->canceledDate = NULL; + } + + $data->status = $task->consumed > 0 ? 'doing' : 'wait'; + $data->statusCustom = strpos(TASKMODEL::CUSTOM_STATUS_ORDER, $data->status) + 1; + $this->dao->update(TABLE_TASK)->data($data)->where('id')->in($this->post->tasks)->exec(); + $this->loadModel('action')->create('task', $task->id, 'moved', '', $task->project); + } + + /* Remove empty story. */ + unset($stories[0]); + + /* Add members to project team. */ + $teamMembers = $this->getTeamMemberPairs($projectID); + foreach($assignedToes as $account => $preProjectID) + { + if(!isset($teamMembers[$account])) + { + $role = $this->dao->select('*')->from(TABLE_TEAM)->where('project')->eq($preProjectID)->andWhere('account')->eq($account)->fetch(); + $role->project = $projectID; + $role->join = helper::today(); + $this->dao->insert(TABLE_TEAM)->data($role)->exec(); + } + } + + /* Link stories. */ + $projectStories = $this->loadModel('story')->getProjectStoryPairs($projectID); + foreach($stories as $storyID) + { + if(!isset($projectStories[$storyID])) + { + $story = $this->dao->findById($storyID)->fields("$projectID as project, id as story, product, version")->from(TABLE_STORY)->fetch(); + $this->dao->insert(TABLE_PROJECTSTORY)->data($story)->exec(); + } + } + } + + /** + * Import task from Bug. + * + * @param int $projectID + * @access public + * @return void + */ + public function importBug($projectID) + { + $this->loadModel('bug'); + $bugLang = $this->app->loadLang('bug'); + $this->loadModel('task'); + $this->loadModel('story'); + + $now = helper::now(); + $BugToTasks = fixer::input('post')->get(); + foreach($BugToTasks->import as $key => $value) + { + $bug = $this->bug->getById($key); + $task->project = $projectID; + $task->story = $bug->story; + $task->storyVersion = $bug->story; + $task->fromBug = $key; + $task->name = $bug->title; + $task->type = 'devel'; + $task->pri = $BugToTasks->pri[$key]; + $task->consumed = 0; + $task->status = 'wait'; + $task->statusCustom = strpos(taskModel::CUSTOM_STATUS_ORDER, 'wait') + 1; + $task->desc = $bugLang->bug->resolve . ':' . '#' . html::a(helper::createLink('bug', 'view', "bugID=$key"), sprintf('%03d', $key)); + $task->openedDate = $now; + $task->openedBy = $this->app->user->account; + if(!empty($BugToTasks->estimate[$key])) + { + $task->estimate = $BugToTasks->estimate[$key]; + $task->left = $task->estimate; + } + if(!empty($BugToTasks->assignedTo[$key])) + { + $task->assignedTo = $BugToTasks->assignedTo[$key]; + $task->assignedDate = $now; + } + $this->dao->insert(TABLE_TASK)->data($task)->checkIF($BugToTasks->estimate[$key] != '', 'estimate', 'float')->exec(); + + if(dao::isError()) + { + echo js::error(dao::getError()); + die(js::reload('parent')); + } + + $taskID = $this->dao->lastInsertID(); + if($task->story != false) $this->story->setStage($task->story); + $actionID = $this->loadModel('action')->create('task', $taskID, 'Opened', ''); + $this->action->create('bug', $key, 'Totask', '', $taskID); + $this->dao->update(TABLE_BUG)->set('toTask')->eq($taskID)->where('id')->eq($key)->exec(); + $mails[$key]->taskID = $taskID; + $mails[$key]->actionID = $actionID; + } + return $mails; + } + + /** + * Get child projects. + * + * @param int $projectID + * @access public + * @return void + */ + public function getChildProjects($projectID) + { + return $this->dao->select('id, name')->from(TABLE_PROJECT)->where('parent')->eq((int)$projectID)->fetchPairs(); + } + + /** + * Update childs. + * + * @param int $projectID + * @access public + * @return void + */ + public function updateChilds($projectID) + { + $sql = "UPDATE " . TABLE_PROJECT . " SET parent = 0 WHERE parent = '$projectID'"; + $this->dbh->exec($sql); + if(!isset($_POST['childs'])) return; + $childs = array_unique($_POST['childs']); + foreach($childs as $childProjectID) + { + $sql = "UPDATE " . TABLE_PROJECT . " SET parent = '$projectID' WHERE id = '$childProjectID'"; + $this->dbh->query($sql); + } + } + + /** + * Link story. + * + * @param int $projectID + * @access public + * @return void + */ + public function linkStory($projectID) + { + if($this->post->stories == false) return false; + $this->loadModel('action'); + $versions = $this->loadModel('story')->getVersions($this->post->stories); + foreach($this->post->stories as $key => $storyID) + { + $productID = $this->post->products[$key]; + $data->project = $projectID; + $data->product = $productID; + $data->story = $storyID; + $data->version = $versions[$storyID]; + $this->dao->insert(TABLE_PROJECTSTORY)->data($data)->exec(); + $this->story->setStage($storyID); + $this->action->create('story', $storyID, 'linked2project', '', $projectID); + } + } + + /** + * Unlink story. + * + * @param int $projectID + * @param int $storyID + * @access public + * @return void + */ + public function unlinkStory($projectID, $storyID) + { + $this->dao->delete()->from(TABLE_PROJECTSTORY)->where('project')->eq($projectID)->andWhere('story')->eq($storyID)->limit(1)->exec(); + $this->loadModel('story')->setStage($storyID); + $this->loadModel('action')->create('story', $storyID, 'unlinkedfromproject', '', $projectID); + $tasks = $this->dao->select('id')->from(TABLE_TASK)->where('story')->eq($storyID)->andWhere('project')->eq($projectID)->andWhere('status')->in('wait,doing')->fetchPairs('id'); + $this->dao->update(TABLE_TASK)->set('status')->eq('cancel')->where('id')->in($tasks)->exec(); + foreach($tasks as $taskID) + { + $changes = $this->loadModel('task')->cancel($taskID); + $actionID = $this->action->create('task', $taskID, 'Canceled'); + $this->action->logHistory($actionID, $changes); + } + } + + /** + * Get team members. + * + * @param int $projectID + * @access public + * @return array + */ + public function getTeamMembers($projectID) + { + return $this->dao->select('t1.*, t1.hours * t1.days AS totalHours, t2.realname')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') + ->where('t1.project')->eq((int)$projectID) + ->andWHere('t2.company')->eq($this->app->company->id) + ->fetchAll('account'); + } + + /** + * Get team members in pair. + * + * @param int $projectID + * @param string $params + * @access public + * @return array + */ + public function getTeamMemberPairs($projectID, $params = '') + { + $users = $this->dao->select('t1.account, t2.realname')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account') + ->where('t1.project')->eq((int)$projectID) + ->andWHere('t2.company')->eq($this->app->company->id) + ->beginIF($params == 'nodeleted') + ->andWhere('t2.deleted')->eq(0) + ->fi() + ->fetchPairs(); + if(!$users) return array(); + foreach($users as $account => $realName) + { + $firstLetter = ucfirst(substr($account, 0, 1)) . ':'; + $users[$account] = $firstLetter . ($realName ? $realName : $account); + } + return array('' => '') + $users; + } + + /** + * Manage team members. + * + * @param int $projectID + * @access public + * @return void + */ + public function manageMembers($projectID) + { + extract($_POST); + + $accounts = array_unique($accounts); + foreach($accounts as $key => $account) + { + if(empty($account)) continue; + + $member->role = $roles[$key]; + $member->days = $days[$key]; + $member->hours = $hours[$key]; + $mode = $modes[$key]; + + if($mode == 'update') + { + $this->dao->update(TABLE_TEAM)->data($member)->where('project')->eq((int)$projectID)->andWhere('account')->eq($account)->exec(); + } + else + { + $member->project = (int)$projectID; + $member->account = $account; + $member->join = helper::today(); + $this->dao->insert(TABLE_TEAM)->data($member)->exec(); + } + } + } + + /** + * Unlink a member. + * + * @param int $projectID + * @param string $account + * @access public + * @return void + */ + public function unlinkMember($projectID, $account) + { + $this->dao->delete()->from(TABLE_TEAM)->where('project')->eq((int)$projectID)->andWhere('account')->eq($account)->exec(); + } + + /** + * Compute burn of a project. + * + * @access public + * @return array + */ + public function computeBurn() + { + $today = helper::today(); + $burns = array(); + + $projects = $this->dao->select('id, name')->from(TABLE_PROJECT) + ->where("end >= '$today'") + ->orWhere('end')->eq('0000-00-00') + ->fetchPairs(); + if(!$projects) return $burns; + + $burns = $this->dao->select("project, '$today' AS date, sum(`left`) AS `left`, SUM(consumed) AS `consumed`") + ->from(TABLE_TASK) + ->where('project')->in(array_keys($projects)) + ->andWhere('deleted')->eq('0') + ->andWhere('status')->notin('cancel,closed') + ->groupBy('project') + ->fetchAll(); + + foreach($burns as $Key => $burn) + { + $this->dao->replace(TABLE_BURN)->data($burn)->exec(); + $burn->projectName = $projects[$burn->project]; + } + return $burns; + } + + /** + * Get data of burn down chart. + * + * @param int $projectID + * @param int $itemCounts + * @access public + * @return array + */ + public function getBurnData($projectID = 0, $itemCounts = 30) + { + /* Get project and burn counts. */ + $project = $this->getById($projectID); + $burnCounts = $this->dao->select('count(*) AS counts')->from(TABLE_BURN)->where('project')->eq($projectID)->fetch('counts'); + + /* If the burnCounts > $itemCounts, get the latest $itemCounts records. */ + $sql = $this->dao->select('date AS name, `left` AS value')->from(TABLE_BURN)->where('project')->eq((int)$projectID); + if($burnCounts > $itemCounts) + { + $sets = $sql->orderBy('date DESC')->limit($itemCounts)->fetchAll('name'); + $sets = array_reverse($sets); + } + else + { + /* The burnCounts < itemCounts, after getting from the db, padding left dates. */ + $sets = $sql->orderBy('date ASC')->fetchAll('name'); + $current = helper::today(); + if($project->end != '0000-00-00') + { + $period = helper::diffDate($project->end, $project->begin) + 1; + $counts = $period > $itemCounts ? $itemCounts : $period; + } + else + { + $counts = $itemCounts; + } + + for($i = 0; $i < $counts - $burnCounts; $i ++) + { + if(helper::diffDate($current, $project->end) > 0) break; + if(!isset($sets[$current])) + { + $sets[$current]->name = $current; + $sets[$current]->value = ''; + } + $nextDay = date(DT_DATE1, strtotime('next day', strtotime($current))); + $current = $nextDay; + } + } + foreach($sets as $set) $set->name = substr($set->name, 5); + return $sets; + } + + public function getBurnDataFlot($projectID = 0, $itemCounts = 30) + { + /* Get project and burn counts. */ + $project = $this->getById($projectID); + $burnCounts = $this->dao->select('count(*) AS counts')->from(TABLE_BURN)->where('project')->eq($projectID)->fetch('counts'); + + /* If the burnCounts > $itemCounts, get the latest $itemCounts records. */ + $sql = $this->dao->select('date AS name, `left` AS value')->from(TABLE_BURN)->where('project')->eq((int)$projectID); + if($burnCounts > $itemCounts) + { + $sets = $sql->orderBy('date DESC')->limit($itemCounts)->fetchAll('name'); + $sets = array_reverse($sets); + } + else + { + /* The burnCounts < itemCounts, after getting from the db, padding left dates. */ + $sets = $sql->orderBy('date ASC')->fetchAll('name'); + $current = helper::today(); + if($project->end != '0000-00-00') + { + $period = helper::diffDate($project->end, $project->begin) + 1; + $counts = $period > $itemCounts ? $itemCounts : $period; + } + else + { + $counts = $itemCounts; + } + + for($i = 0; $i < $counts - $burnCounts; $i ++) + { + if(helper::diffDate($current, $project->end) > 0) break; + if(!isset($sets[$current])) + { + $sets[$current]->name = $current; + $sets[$current]->value = ''; + } + $nextDay = date(DT_DATE1, strtotime('next day', strtotime($current))); + $current = $nextDay; + } + } + $count = 0; + foreach($sets as $set) + { + $set->name = (string)strtotime("$set->name UTC") . '000'; + $count ++; + } + $sets['count'] = $count; + return $sets; + } + + /** + * Get taskes by search. + * + * @param string $condition + * @param object $pager + * @param string $orderBy + * @access public + * @return array + */ + public function getSearchTasks($condition, $pager, $orderBy) + { + $taskIdList = $this->dao->select('id') + ->from(TABLE_TASK) + ->where($condition) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + + $tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') + ->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->leftJoin(TABLE_USER)->alias('t3')->on('t1.assignedTo = t3.account') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.id')->in(array_keys($taskIdList)) + ->orderBy($orderBy) + ->fetchAll(); + return $tasks; + } + + /** + * Get bugs by search in project. + * + * @param int $products + * @param int $projectID + * @param int $sql + * @param int $pager + * @param int $orderBy + * @access public + * @return void + */ + public function getSearchBugs($products, $projectID, $sql, $pager, $orderBy) + { + return $this->dao->select('*')->from(TABLE_BUG) + ->where($sql) + ->andWhere('status')->eq('active') + ->andWhere('toTask')->eq(0) + ->andWhere('tostory')->eq(0) + ->beginIF(!empty($products))->andWhere('product')->in(array_keys($products))->fi() + ->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } + + /** + * Get resolved bugs of a project + * + * @param int $projectID + * @access public + * @return array + */ + public function getResolvedBugs($projectID) + { + $project = $this->getById($projectID); + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); + return $this->dao->select('id, title, status')->from(TABLE_BUG) + ->where('status')->eq('resolved') + ->andWhere('resolvedDate')->ge($project->begin) + ->andWhere('resolution')->eq('fixed') + ->andWhere('product')->in($products) + ->fetchAll(); + } +} diff --git a/module/project/view/browse.html.php b/module/project/view/browse.html.php index 992ea1bba2..df0f029fbc 100644 --- a/module/project/view/browse.html.php +++ b/module/project/view/browse.html.php @@ -1,154 +1,154 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -
          -
          - - - - - - - - - - - - - - - - - - - - - - -
          - project->selectProject;?> - id, 'onchange="selectProject(this.value);" style="width:200px"');?> -
          project->name;?>name;?>
          project->code;?>code;?>
          project->begin;?>begin;?>
          project->end;?>end;?>
          - createLink('project', 'edit', "projectID=$project->id"), $lang->project->edit); - if(common::hasPriv('project', 'delete')) echo html::a($this->createLink('project', 'delete', "projectID=$project->id"), $lang->project->delete, 'hiddenwin'); - //echo html::a($this->createLink('tree', 'browse', "productID=$productID&view=product"), $lang->tree->manage); - ?> -
          - - - - - -
          - project->products;?> -
          - $productName) echo html::a($this->createLink('product', 'browse', "productID=$productID"), $productName) . '
          ';?> -
          - createLink('project', 'manageproducts', "projectID=$project->id"), $lang->project->manageProducts); - if(common::hasPriv('project', 'linkstory')) echo html::a($this->createLink('project', 'linkstory', "projectID=$project->id"), $lang->project->linkStory); - ?> -
          -
          - - - - - - - - - - $lang->actions";?> - - - - - - - - - - " . html::a($this->createLink('project', 'unlinkmember', "projectID=$project->id&account=$member->account"), $lang->project->unlinkMember, 'hiddenwin') . '';?> - - - -
          - project->team . $lang->colon . $project->team; ?> -
          team->account;?>team->role;?>team->joinDate;?>team->workingHour;?>
          - createLink('user', 'view', "account=$member->account"), $member->realname); - else echo $member->realname; - ?> - role;?>joinDate, 2);?>workingHour;?>
          -
          - createLink('project', 'managemembers', "projectID=$project->id"), $lang->project->manageMembers) . '
          ';?> -
          - -
          -
          -
          -
          -
            - $project->name"; - echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=task"), $lang->project->tasks) . "
          • "; - echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=story"), $lang->project->stories) . "
          • "; - //echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=bug"), $lang->project->bugs) . "
          • "; - //echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=burn"), $lang->project->burndown) . "
          • "; - echo << -$("#{$tabID}tab").addClass('active'); - -EOT; - ?> -
          - -
          createLink('task', 'create', "project=$project->id"), $lang->task->create);?>
          - -
          createLink('project', 'linkstory', "project=$project->id"), $lang->project->linkStory);?>
          - -
          - -
          -
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +
          +
          + + + + + + + + + + + + + + + + + + + + + + +
          + project->selectProject;?> + id, 'onchange="selectProject(this.value);" style="width:200px"');?> +
          project->name;?>name;?>
          project->code;?>code;?>
          project->begin;?>begin;?>
          project->end;?>end;?>
          + createLink('project', 'edit', "projectID=$project->id"), $lang->project->edit); + if(common::hasPriv('project', 'delete')) echo html::a($this->createLink('project', 'delete', "projectID=$project->id"), $lang->project->delete, 'hiddenwin'); + //echo html::a($this->createLink('tree', 'browse', "productID=$productID&view=product"), $lang->tree->manage); + ?> +
          + + + + + +
          + project->products;?> +
          + $productName) echo html::a($this->createLink('product', 'browse', "productID=$productID"), $productName) . '
          ';?> +
          + createLink('project', 'manageproducts', "projectID=$project->id"), $lang->project->manageProducts); + if(common::hasPriv('project', 'linkstory')) echo html::a($this->createLink('project', 'linkstory', "projectID=$project->id"), $lang->project->linkStory); + ?> +
          +
          + + + + + + + + + + $lang->actions";?> + + + + + + + + + + " . html::a($this->createLink('project', 'unlinkmember', "projectID=$project->id&account=$member->account"), $lang->project->unlinkMember, 'hiddenwin') . '';?> + + + +
          + project->team . $lang->colon . $project->team; ?> +
          team->account;?>team->role;?>team->joinDate;?>team->workingHour;?>
          + createLink('user', 'view', "account=$member->account"), $member->realname); + else echo $member->realname; + ?> + role;?>joinDate, 2);?>workingHour;?>
          +
          + createLink('project', 'managemembers', "projectID=$project->id"), $lang->project->manageMembers) . '
          ';?> +
          + +
          +
          +
          +
          +
            + $project->name"; + echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=task"), $lang->project->tasks) . "
          • "; + echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=story"), $lang->project->stories) . "
          • "; + //echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=bug"), $lang->project->bugs) . "
          • "; + //echo "
          • " . html::a($this->createLink('project', 'browse', "projectID=$project->id&tabID=burn"), $lang->project->burndown) . "
          • "; + echo << +$("#{$tabID}tab").addClass('active'); + +EOT; + ?> +
          + +
          createLink('task', 'create', "project=$project->id"), $lang->task->create);?>
          + +
          createLink('project', 'linkstory', "project=$project->id"), $lang->project->linkStory);?>
          + +
          + +
          +
          +
          + diff --git a/module/project/view/bug.html.php b/module/project/view/bug.html.php index c18f37359f..946a0c121a 100644 --- a/module/project/view/bug.html.php +++ b/module/project/view/bug.html.php @@ -1,63 +1,63 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - id}&orderBy=%s&build=$buildID&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          - project->bug; - if($build) echo '(Build:' . $build->name . ')'; - ?> -
          -
          id", $lang->bug->create);?>
          -
          idAB);?>bug->severityAB);?> priAB);?> bug->title);?> openedByAB);?> assignedToAB);?> bug->resolvedBy);?>bug->resolutionAB);?>actions;?>
          createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?> - id"; - if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; - if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; - common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); - ?> -
          show();?>
          - - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + id}&orderBy=%s&build=$buildID&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          + project->bug; + if($build) echo '(Build:' . $build->name . ')'; + ?> +
          +
          id", $lang->bug->create);?>
          +
          idAB);?>bug->severityAB);?> priAB);?> bug->title);?> openedByAB);?> assignedToAB);?> bug->resolvedBy);?>bug->resolutionAB);?>actions;?>
          createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>assignedTo];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?> + id"; + if(!($bug->status == 'active' and common::printLink('bug', 'resolve', $params, $lang->bug->buttonResolve))) echo $lang->bug->buttonResolve . ' '; + if(!($bug->status == 'resolved' and common::printLink('bug', 'close', $params, $lang->bug->buttonClose))) echo $lang->bug->buttonClose . ' '; + common::printLink('bug', 'edit', $params, $lang->bug->buttonEdit); + ?> +
          show();?>
          + + diff --git a/module/project/view/build.html.php b/module/project/view/build.html.php index baecbb725a..266a9b7ccf 100644 --- a/module/project/view/build.html.php +++ b/module/project/view/build.html.php @@ -1,54 +1,54 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          project->build;?>
          -
          id", $lang->build->create);?>
          -
          build->id;?>build->product;?>build->name;?>build->scmPath;?>build->filePath;?>build->date;?>build->builder;?>actions;?>
          id;?>productName;?>createLink('build', 'view', "build=$build->id"), $build->name);?>scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>date?>builder]?> - id&build=$build->id", $lang->testtask->create); - common::printLink('project', 'bug', "project=$project->id&orderBy=status&build=$build->id", $lang->project->viewBug); - common::printLink('build', 'edit', "buildID=$build->id", $lang->edit); - common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin'); - ?> -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          project->build;?>
          +
          id", $lang->build->create);?>
          +
          build->id;?>build->product;?>build->name;?>build->scmPath;?>build->filePath;?>build->date;?>build->builder;?>actions;?>
          id;?>productName;?>createLink('build', 'view', "build=$build->id"), $build->name);?>scmPath, 'http') === 0 ? printf(html::a($build->scmPath)) : printf($build->scmPath);?>filePath, 'http') === 0 ? printf(html::a($build->filePath)) : printf($build->filePath);?>date?>builder]?> + id&build=$build->id", $lang->testtask->create); + common::printLink('project', 'bug', "project=$project->id&orderBy=status&build=$build->id", $lang->project->viewBug); + common::printLink('build', 'edit', "buildID=$build->id", $lang->edit); + common::printLink('build', 'delete', "buildID=$build->id", $lang->delete, 'hiddenwin'); + ?> +
          + diff --git a/module/project/view/burn.html.php b/module/project/view/burn.html.php index 23954406d3..653ba3fd18 100644 --- a/module/project/view/burn.html.php +++ b/module/project/view/burn.html.php @@ -1,21 +1,21 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - project->computeBurn, 'hiddenwin'); - printf($lang->project->howToUpdateBurn, $this->createLink('help', 'field', 'module=project&method-burn&field=updateburn')); - ?> -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + project->computeBurn, 'hiddenwin'); + printf($lang->project->howToUpdateBurn, $this->createLink('help', 'field', 'module=project&method-burn&field=updateburn')); + ?> +
          + diff --git a/module/project/view/computeburn.html.php b/module/project/view/computeburn.html.php index fd8d3e2bac..10b5c1811a 100644 --- a/module/project/view/computeburn.html.php +++ b/module/project/view/computeburn.html.php @@ -1,18 +1,18 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> -project . "\t" . $burn->projectName . "\t" . $burn->date . "\t" . $burn->left . "\n"; -} -?> + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> +project . "\t" . $burn->projectName . "\t" . $burn->date . "\t" . $burn->left . "\n"; +} +?> diff --git a/module/project/view/create.html.php b/module/project/view/create.html.php index 680ac3c378..36d4fc19e2 100644 --- a/module/project/view/create.html.php +++ b/module/project/view/create.html.php @@ -1,86 +1,86 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > - - - - - - -
          project->create;?>
          project->name;?>
          project->code;?>
          project->begin;?>
          project->end;?>
          project->days;?>
          project->teamname;?>
          project->manageProducts;?>
          project->goal;?>
          project->desc;?>
          project->acl;?>project->aclList, $acl, "onclick='setWhite(this.value);'"));?>
          project->whitelist;?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + +
          project->create;?>
          project->name;?>
          project->code;?>
          project->begin;?>
          project->end;?>
          project->days;?>
          project->teamname;?>
          project->manageProducts;?>
          project->goal;?>
          project->desc;?>
          project->acl;?>project->aclList, $acl, "onclick='setWhite(this.value);'"));?>
          project->whitelist;?>
          +
          + diff --git a/module/project/view/doc.html.php b/module/project/view/doc.html.php index aa9165566a..b753eb56a0 100644 --- a/module/project/view/doc.html.php +++ b/module/project/view/doc.html.php @@ -1,51 +1,51 @@ - - * @package product - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - $doc):?> - createLink('doc', 'view', "docID=$doc->id"); - $canView = common::hasPriv('doc', 'view'); - ?> - - - - - - - - - - -
          id&from=project", $lang->doc->create);?>
          idAB;?>doc->module;?>doc->title;?>doc->addedBy;?>doc->addedDate;?>actions;?>
          id)); else printf('%03d', $doc->id);?>module]);?>title);?>addedBy];?>addedDate;?> - id}"; - if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; - if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; - ?> -
          - + + * @package product + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + $doc):?> + createLink('doc', 'view', "docID=$doc->id"); + $canView = common::hasPriv('doc', 'view'); + ?> + + + + + + + + + + +
          id&from=project", $lang->doc->create);?>
          idAB;?>doc->module;?>doc->title;?>doc->addedBy;?>doc->addedDate;?>actions;?>
          id)); else printf('%03d', $doc->id);?>module]);?>title);?>addedBy];?>addedDate;?> + id}"; + if(!common::printLink('doc', 'edit', $vars, $lang->edit)) echo $lang->edit; + if(!common::printLink('doc', 'delete', $vars, $lang->delete, 'hiddenwin')) echo $lang->delete; + ?> +
          + diff --git a/module/project/view/dynamic.html.php b/module/project/view/dynamic.html.php index d708729b6a..7be0fc5b92 100755 --- a/module/project/view/dynamic.html.php +++ b/module/project/view/dynamic.html.php @@ -1,56 +1,56 @@ -dynamic view file of dashboard module of ZenTaoPMS. - * - * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) - * @license LGPL (http://www.gnu.org/licenses/lgpl.html) - * @author Chunsheng Wang - * @package dashboard - * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ - * @link http://www.zentao.net - */ -?> - - -
          - ' . html::a(inlink('dynamic', "projectID=$projectID&type=today"), $lang->action->dynamic->today) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=yesterday"), $lang->action->dynamic->yesterday) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=thisweek"), $lang->action->dynamic->thisWeek) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=lastweek"), $lang->action->dynamic->lastWeek) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=thismonth"), $lang->action->dynamic->thisMonth) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; - echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=all"), $lang->action->dynamic->all) . ''; - echo "" . html::select('account', $users, $account, "onchange=changeUser(this.value,$projectID)") . ''; - ?> -
          - - - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - -
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          - - +dynamic view file of dashboard module of ZenTaoPMS. + * + * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) + * @license LGPL (http://www.gnu.org/licenses/lgpl.html) + * @author Chunsheng Wang + * @package dashboard + * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ + * @link http://www.zentao.net + */ +?> + + +
          + ' . html::a(inlink('dynamic', "projectID=$projectID&type=today"), $lang->action->dynamic->today) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=yesterday"), $lang->action->dynamic->yesterday) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=twodaysago"), $lang->action->dynamic->twoDaysAgo) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=thisweek"), $lang->action->dynamic->thisWeek) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=lastweek"), $lang->action->dynamic->lastWeek) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=thismonth"), $lang->action->dynamic->thisMonth) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=lastmonth"), $lang->action->dynamic->lastMonth) . ''; + echo '' . html::a(inlink('dynamic', "projectID=$projectID&type=all"), $lang->action->dynamic->all) . ''; + echo "" . html::select('account', $users, $account, "onchange=changeUser(this.value,$projectID)") . ''; + ?> +
          + + + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + +
          action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
          date;?>actor]) ? print($users[$action->actor]) : print($action->actor);?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
          show();?>
          + + diff --git a/module/project/view/edit.html.php b/module/project/view/edit.html.php index a8d7310e60..e05237f63d 100644 --- a/module/project/view/edit.html.php +++ b/module/project/view/edit.html.php @@ -1,86 +1,86 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - acl != 'custom') echo "class='hidden'";?>> - - - - -
          project->edit;?>
          project->name;?>name, "class='text-3'");?>
          project->code;?>code, "class='text-3'");?>
          project->begin;?>begin, "class='text-3 date' onchange='computeWorkDays()'");?>
          project->end;?>end, "class='text-3 date' onchange='computeWorkDays()'");?>
          project->days;?>days, "class='text-3'");?>
          project->teamname;?>team, "class='text-3'");?>
          project->status;?>project->statusList, $project->status, 'class=text-3');?>
          project->PO;?>PO, 'class=text-3');?>
          project->PM;?>PM, 'class=text-3');?>
          project->QM;?>QM, 'class=text-3');?>
          project->RM;?>RM, 'class=text-3');?>
          project->manageProducts;?>
          project->goal;?>goal), "rows='6' class='area-1'");?>
          project->desc;?>desc), "rows='6' class='area-1'");?>
          project->acl;?>project->aclList, $project->acl, "onclick='setWhite(this.value);'"));?>
          project->whitelist;?>whitelist);?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + acl != 'custom') echo "class='hidden'";?>> + + + + +
          project->edit;?>
          project->name;?>name, "class='text-3'");?>
          project->code;?>code, "class='text-3'");?>
          project->begin;?>begin, "class='text-3 date' onchange='computeWorkDays()'");?>
          project->end;?>end, "class='text-3 date' onchange='computeWorkDays()'");?>
          project->days;?>days, "class='text-3'");?>
          project->teamname;?>team, "class='text-3'");?>
          project->status;?>project->statusList, $project->status, 'class=text-3');?>
          project->PO;?>PO, 'class=text-3');?>
          project->PM;?>PM, 'class=text-3');?>
          project->QM;?>QM, 'class=text-3');?>
          project->RM;?>RM, 'class=text-3');?>
          project->manageProducts;?>
          project->goal;?>goal), "rows='6' class='area-1'");?>
          project->desc;?>desc), "rows='6' class='area-1'");?>
          project->acl;?>project->aclList, $project->acl, "onclick='setWhite(this.value);'"));?>
          project->whitelist;?>whitelist);?>
          +
          + diff --git a/module/project/view/grouptask.html.php b/module/project/view/grouptask.html.php index a256b33e2a..de40e72529 100644 --- a/module/project/view/grouptask.html.php +++ b/module/project/view/grouptask.html.php @@ -1,118 +1,118 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - $groupTasks):?> - - - - - - - - assignedTo == $app->user->account ? 'style=color:red' : '';?> - createLink('task','view',"taskID=$task->id"); ?> - estimate; - $totalConsumed += $task->consumed; - $totalLeft += ($task->status == 'cancel' ? 0 : $task->left); - - $groupEstimate += $task->estimate; - $groupConsumed += $task->consumed; - $groupLeft += ($task->status == 'cancel' ? 0 : $task->left); - - if($task->status == 'wait') - { - $statusWait++; - $groupWait++; - } - elseif($task->status == 'doing') - { - $statusDoing++; - $groupDoing++; - } - elseif($task->status == 'done') - { - $statusDone++; - $groupDone++; - } - elseif($task->status == 'closed') - { - $statusClosed++; - $groupClosed++; - } - $groupSum = count($groupTasks); - $taskSum += count($tasks); - ?> - - - - - - - - - - - - - - - - - - - -
          task->name;?> priAB;?>task->assignedTo;?>task->finishedBy;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>typeAB;?>task->deadlineAB;?>task->status;?>
           id . $lang->colon; if(common::hasPriv('task', 'view')) echo html::a($this->createLink('task', 'view', "task=$task->id"), $task->name); else echo $task->name;?>pri;?>>assignedToRealName;?>finishedBy];?>estimate;?>consumed;?>left;?>task->typeList[$task->type];?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>status;?> >task->statusList[$task->status];?> - createLink('task', 'edit', "taskid=$task->id"), $lang->edit);?> - createLink('task', 'delete', "projectID=$task->project&taskid=$task->id"), $lang->delete, 'hiddenwin');?> -
          - assignedTo])) printf($lang->project->memberHours, $users[$task->assignedTo], $members[$task->assignedTo]->totalHours);?> - project->groupSummary, $groupSum, $groupWait, $groupDoing, $groupEstimate, $groupConsumed, $groupLeft);?> -
          - - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + $groupTasks):?> + + + + + + + + assignedTo == $app->user->account ? 'style=color:red' : '';?> + createLink('task','view',"taskID=$task->id"); ?> + estimate; + $totalConsumed += $task->consumed; + $totalLeft += ($task->status == 'cancel' ? 0 : $task->left); + + $groupEstimate += $task->estimate; + $groupConsumed += $task->consumed; + $groupLeft += ($task->status == 'cancel' ? 0 : $task->left); + + if($task->status == 'wait') + { + $statusWait++; + $groupWait++; + } + elseif($task->status == 'doing') + { + $statusDoing++; + $groupDoing++; + } + elseif($task->status == 'done') + { + $statusDone++; + $groupDone++; + } + elseif($task->status == 'closed') + { + $statusClosed++; + $groupClosed++; + } + $groupSum = count($groupTasks); + $taskSum += count($tasks); + ?> + + + + + + + + + + + + + + + + + + + +
          task->name;?> priAB;?>task->assignedTo;?>task->finishedBy;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>typeAB;?>task->deadlineAB;?>task->status;?>
           id . $lang->colon; if(common::hasPriv('task', 'view')) echo html::a($this->createLink('task', 'view', "task=$task->id"), $task->name); else echo $task->name;?>pri;?>>assignedToRealName;?>finishedBy];?>estimate;?>consumed;?>left;?>task->typeList[$task->type];?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>status;?> >task->statusList[$task->status];?> + createLink('task', 'edit', "taskid=$task->id"), $lang->edit);?> + createLink('task', 'delete', "projectID=$task->project&taskid=$task->id"), $lang->delete, 'hiddenwin');?> +
          + assignedTo])) printf($lang->project->memberHours, $users[$task->assignedTo], $members[$task->assignedTo]->totalHours);?> + project->groupSummary, $groupSum, $groupWait, $groupDoing, $groupEstimate, $groupConsumed, $groupLeft);?> +
          + + diff --git a/module/project/view/importbug.html.php b/module/project/view/importbug.html.php index 4a90fb8145..d93ad87e07 100755 --- a/module/project/view/importbug.html.php +++ b/module/project/view/importbug.html.php @@ -1,62 +1,62 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          -
          -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          import;?> idAB;?> bug->severityAB;?> priAB;?>bug->title;?>bug->statusAB;?>task->pri;?>task->assignedTo;?>task->estimate;?>
          id]", '');?> id) . html::hidden("id[$bug->id]", $bug->id);?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>id", $bug->title, '', "class='preview'");?>bug->statusList[$bug->status];?>id]", $lang->task->priList, 3);?>id]", $users, '');?>id]", '', 'size=4');?>
          show();?>
          -
          import) . html::resetButton();?>
          -
          -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          import;?> idAB;?> bug->severityAB;?> priAB;?>bug->title;?>bug->statusAB;?>task->pri;?>task->assignedTo;?>task->estimate;?>
          id]", '');?> id) . html::hidden("id[$bug->id]", $bug->id);?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>id", $bug->title, '', "class='preview'");?>bug->statusList[$bug->status];?>id]", $lang->task->priList, 3);?>id]", $users, '');?>id]", '', 'size=4');?>
          show();?>
          +
          import) . html::resetButton();?>
          +
          +
          + diff --git a/module/project/view/importtask.html.php b/module/project/view/importtask.html.php index 1634b151c9..add959eacb 100644 --- a/module/project/view/importtask.html.php +++ b/module/project/view/importtask.html.php @@ -1,59 +1,59 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - assignedTo == $app->user->account ? 'style=color:red' : '';?> - - - - - - - - - - - - - - -
          task->project;?>idAB;?>priAB;?>task->name;?>task->assignedTo;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>task->story;?>import;?>
          project];?>id", sprintf('%03d', $task->id))) printf('%03d', $task->id);?>pri;?>id", $task->name)) echo $task->name;?>>assignedToRealName;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>status;?> >task->statusList[$task->status];?> - storyID) - { - if(common::hasPriv('story', 'view')) echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); - else echo $task->storyTitle; - } - ?> -
          -
          project->importTask);?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + assignedTo == $app->user->account ? 'style=color:red' : '';?> + + + + + + + + + + + + + + +
          task->project;?>idAB;?>priAB;?>task->name;?>task->assignedTo;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>task->story;?>import;?>
          project];?>id", sprintf('%03d', $task->id))) printf('%03d', $task->id);?>pri;?>id", $task->name)) echo $task->name;?>>assignedToRealName;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>status;?> >task->statusList[$task->status];?> + storyID) + { + if(common::hasPriv('story', 'view')) echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); + else echo $task->storyTitle; + } + ?> +
          +
          project->importTask);?>
          +
          + diff --git a/module/project/view/index.html.php b/module/project/view/index.html.php index 4ae81bd4c7..4df7cf4d01 100644 --- a/module/project/view/index.html.php +++ b/module/project/view/index.html.php @@ -1,48 +1,48 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -?> - - - -

          - project->unDoneProjects);?> - project->doneProjects);?> -

          - - - - - - - - - - - - - - - - - - - - - - - - - -
          project->name;?>project->code;?>project->end;?>project->status;?>project->totalEstimate;?>project->totalConsumed;?>project->totalLeft;?>project->progess;?>project->burn;?>
          createLink('project', 'task', 'project=' . $project->id), $project->name, '_parent');?>code;?>end;?>project->statusList[$project->status];?>hours->totalEstimate;?>hours->totalConsumed;?>hours->totalLeft;?> - hours->progress;?> height='13' text-align: /> - hours->progress;?>% - burns);?>'>
          - + + * @package ZenTaoPMS + * @version $Id$ + */ +?> + + + +

          + project->unDoneProjects);?> + project->doneProjects);?> +

          + + + + + + + + + + + + + + + + + + + + + + + + + +
          project->name;?>project->code;?>project->end;?>project->status;?>project->totalEstimate;?>project->totalConsumed;?>project->totalLeft;?>project->progess;?>project->burn;?>
          createLink('project', 'task', 'project=' . $project->id), $project->name, '_parent');?>code;?>end;?>project->statusList[$project->status];?>hours->totalEstimate;?>hours->totalConsumed;?>hours->totalLeft;?> + hours->progress;?> height='13' text-align: /> + hours->progress;?>% + burns);?>'>
          + diff --git a/module/project/view/linkstory.html.php b/module/project/view/linkstory.html.php index 814bbc49da..52f241fa86 100644 --- a/module/project/view/linkstory.html.php +++ b/module/project/view/linkstory.html.php @@ -1,53 +1,53 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - id])) continue;?> - createLink('story', 'view', "storyID=$story->id");?> - - - - - - - - - - - - - - -
          idAB;?>priAB;?>story->product;?>story->title;?>story->plan;?>openedByAB;?>story->estimateAB;?>link;?>
          id);?>story->priList[$story->pri];?>createLink('product', 'browse', "productID=$story->product"), $products[$story->product], '_blank');?>title);?>planTitle;?>openedBy];?>estimate;?> - - -
          project->whyNoStories);?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + id])) continue;?> + createLink('story', 'view', "storyID=$story->id");?> + + + + + + + + + + + + + + +
          idAB;?>priAB;?>story->product;?>story->title;?>story->plan;?>openedByAB;?>story->estimateAB;?>link;?>
          id);?>story->priList[$story->pri];?>createLink('product', 'browse', "productID=$story->product"), $products[$story->product], '_blank');?>title);?>planTitle;?>openedBy];?>estimate;?> + + +
          project->whyNoStories);?>
          +
          + diff --git a/module/project/view/managechilds.html.php b/module/project/view/managechilds.html.php index e1bb56fc4b..7b7c4c0e14 100644 --- a/module/project/view/managechilds.html.php +++ b/module/project/view/managechilds.html.php @@ -1,29 +1,29 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          - - - - - - -
          project->manageChilds;?>
          - -
          -
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +
          + + + + + + +
          project->manageChilds;?>
          + +
          +
          +
          + diff --git a/module/project/view/managemembers.html.php b/module/project/view/managemembers.html.php index 704507d904..9e0f9d2b7b 100644 --- a/module/project/view/managemembers.html.php +++ b/module/project/view/managemembers.html.php @@ -1,60 +1,60 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - $member):?> - account], 2);?> - account]);?> - - - - - - - - - PROJECTMODEL::LINK_MEMBERS_ONE_TIME) $count = PROJECTMODEL::LINK_MEMBERS_ONE_TIME; - ?> - - - - - - - - - - - - -
          project->manageMembers;?>
          team->account;?>team->role;?>team->days;?>team->hours;?>
          - - -
          - - -
          - -
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + $member):?> + account], 2);?> + account]);?> + + + + + + + + + PROJECTMODEL::LINK_MEMBERS_ONE_TIME) $count = PROJECTMODEL::LINK_MEMBERS_ONE_TIME; + ?> + + + + + + + + + + + + +
          project->manageMembers;?>
          team->account;?>team->role;?>team->days;?>team->hours;?>
          + + +
          + + +
          + +
          +
          + diff --git a/module/project/view/manageproducts.html.php b/module/project/view/manageproducts.html.php index dab3b90a3d..ee2f59ec3b 100644 --- a/module/project/view/manageproducts.html.php +++ b/module/project/view/manageproducts.html.php @@ -1,23 +1,23 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - -
          project->manageProducts;?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + +
          project->manageProducts;?>
          +
          + diff --git a/module/project/view/sendmail.html.php b/module/project/view/sendmail.html.php index 0315536249..882987f19f 100644 --- a/module/project/view/sendmail.html.php +++ b/module/project/view/sendmail.html.php @@ -1,22 +1,22 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          - TASK #id . "=>$task->assignedTo " . html::a(common::getSysURL() . $this->createLink('task', 'view', "taskID=$task->id"), $task->name);?> -
          + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          + TASK #id . "=>$task->assignedTo " . html::a(common::getSysURL() . $this->createLink('task', 'view', "taskID=$task->id"), $task->name);?> +
          diff --git a/module/project/view/story.html.php b/module/project/view/story.html.php index c42bbd3047..fe7aa328d8 100644 --- a/module/project/view/story.html.php +++ b/module/project/view/story.html.php @@ -1,74 +1,74 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - id}&orderBy=%s"; ?> - - - - - - - - - - - - - - - $story):?> - createLink('story', 'view', "storyID=$story->id"); - $totalEstimate += $story->estimate; - ?> - - - - - - - - - - - - - - - -
          -
          project->story;?>
          -
          - id", $lang->story->create); - if(common::hasPriv('project', 'linkstory')) echo html::a($this->createLink('project', 'linkstory', "project=$project->id"), $lang->project->linkStory); - ?> -
          -
          idAB);?> priAB);?> story->title);?> openedByAB);?> assignedToAB);?> story->estimateAB);?> statusAB);?> story->stageAB);?> story->taskCount;?> actions;?>
          id));?>story->priList[$story->pri];?>title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> - id}&story={$story->id}"; - common::printLink('task', 'create', $param, $lang->project->wbs); - common::printLink('project', 'unlinkStory', $param, $lang->unlink, 'hiddenwin'); - ?> -
          product->storySummary, count($stories), $totalEstimate);?>
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + id}&orderBy=%s"; ?> + + + + + + + + + + + + + + + $story):?> + createLink('story', 'view', "storyID=$story->id"); + $totalEstimate += $story->estimate; + ?> + + + + + + + + + + + + + + + +
          +
          project->story;?>
          +
          + id", $lang->story->create); + if(common::hasPriv('project', 'linkstory')) echo html::a($this->createLink('project', 'linkstory', "project=$project->id"), $lang->project->linkStory); + ?> +
          +
          idAB);?> priAB);?> story->title);?> openedByAB);?> assignedToAB);?> story->estimateAB);?> statusAB);?> story->stageAB);?> story->taskCount;?> actions;?>
          id));?>story->priList[$story->pri];?>title);?>openedBy];?>assignedTo];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?> + id}&story={$story->id}"; + common::printLink('task', 'create', $param, $lang->project->wbs); + common::printLink('project', 'unlinkStory', $param, $lang->unlink, 'hiddenwin'); + ?> +
          product->storySummary, count($stories), $totalEstimate);?>
          + diff --git a/module/project/view/task.html.php b/module/project/view/task.html.php index 0ab4c8d7d1..af390e5fbd 100644 --- a/module/project/view/task.html.php +++ b/module/project/view/task.html.php @@ -1,124 +1,124 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - -
          '>
          - - id&status=$status&parma=$param&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage"; ?> - - - - - - - - - cookie->windowWidth > $this->config->wideSize):?> - - - - - - - cookie->windowWidth > $this->config->wideSize):?> - - - - - - - - - - - - - - assignedTo == $app->user->account ? 'style=color:red' : '';?> - estimate; - $totalConsumed += $task->consumed; - $totalLeft += (($task->status == 'cancel' or $task->closedReason == 'cancel') ? 0 : $task->left); - $statusVar = 'status' . ucfirst($task->status); - $$statusVar ++; - ?> - - - - - - - - - cookie->windowWidth > $this->config->wideSize):?> - - - - cookie->windowWidth > $this->config->wideSize):?> - - - - - - - - - - - cookie->windowWidth > $this->config->wideSize ? 14 : 12;?> - - - -
          idAB);?> priAB);?> task->name);?>statusAB);?> task->deadlineAB);?> task->openedDateAB);?> task->assignedToAB);?> task->finishedByAB);?> task->finishedDateAB);?> task->estimateAB);?> task->consumedAB);?> task->leftAB);?>task->story);?>actions;?>
          id", sprintf('%03d', $task->id))) printf('%03d', $task->id);?>task->priList[$task->pri];?> - fromBug != 0) echo "[BUG] "; - else echo "[TASK] "; - if(!common::printLink('task', 'view', "task=$task->id", $task->name)) echo $task->name; - ?> - status;?> > - storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion); - $storyChanged ? print("{$lang->story->changed} ") : print($lang->task->statusList[$task->status]); - ?> - delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo substr($task->deadline, 5, 6);?>openedDate, 5, 6);?> - - - >assignedToRealName;?>finishedBy];?>finishedDate, 5, 6);?> - - - estimate;?>consumed;?>left;?> - storyID and common::hasPriv('story', 'view')) $story = html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); - if($task->storyID and !common::hasPriv('story', 'view')) $story = $task->storyTitle; - echo $story; - ?> - - status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; - if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; - if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; - if($browseType == 'needconfirm') common::printLink('task', 'confirmStoryChange', "taskid=$task->id", $lang->confirm, 'hiddenwin'); - ?> -
          -
          project->taskSummary, count($tasks), $statusWait, $statusDoing, $totalEstimate, $totalConsumed, $totalLeft);?>
          - show();?> -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + +
          '>
          + + id&status=$status&parma=$param&orderBy=%s&recTotal=$recTotal&recPerPage=$recPerPage"; ?> + + + + + + + + + cookie->windowWidth > $this->config->wideSize):?> + + + + + + + cookie->windowWidth > $this->config->wideSize):?> + + + + + + + + + + + + + + assignedTo == $app->user->account ? 'style=color:red' : '';?> + estimate; + $totalConsumed += $task->consumed; + $totalLeft += (($task->status == 'cancel' or $task->closedReason == 'cancel') ? 0 : $task->left); + $statusVar = 'status' . ucfirst($task->status); + $$statusVar ++; + ?> + + + + + + + + + cookie->windowWidth > $this->config->wideSize):?> + + + + cookie->windowWidth > $this->config->wideSize):?> + + + + + + + + + + + cookie->windowWidth > $this->config->wideSize ? 14 : 12;?> + + + +
          idAB);?> priAB);?> task->name);?>statusAB);?> task->deadlineAB);?> task->openedDateAB);?> task->assignedToAB);?> task->finishedByAB);?> task->finishedDateAB);?> task->estimateAB);?> task->consumedAB);?> task->leftAB);?>task->story);?>actions;?>
          id", sprintf('%03d', $task->id))) printf('%03d', $task->id);?>task->priList[$task->pri];?> + fromBug != 0) echo "[BUG] "; + else echo "[TASK] "; + if(!common::printLink('task', 'view', "task=$task->id", $task->name)) echo $task->name; + ?> + status;?> > + storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion); + $storyChanged ? print("{$lang->story->changed} ") : print($lang->task->statusList[$task->status]); + ?> + delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo substr($task->deadline, 5, 6);?>openedDate, 5, 6);?> + + + >assignedToRealName;?>finishedBy];?>finishedDate, 5, 6);?> + + + estimate;?>consumed;?>left;?> + storyID and common::hasPriv('story', 'view')) $story = html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); + if($task->storyID and !common::hasPriv('story', 'view')) $story = $task->storyTitle; + echo $story; + ?> + + status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; + if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; + if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; + if($browseType == 'needconfirm') common::printLink('task', 'confirmStoryChange', "taskid=$task->id", $lang->confirm, 'hiddenwin'); + ?> +
          +
          project->taskSummary, count($tasks), $statusWait, $statusDoing, $totalEstimate, $totalConsumed, $totalLeft);?>
          + show();?> +
          + diff --git a/module/project/view/team.html.php b/module/project/view/team.html.php index c038f3aa0e..06d8d95b8d 100644 --- a/module/project/view/team.html.php +++ b/module/project/view/team.html.php @@ -1,56 +1,56 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - $lang->actions";?> - - - - - - - - - - - - - " . html::a($this->createLink('project', 'unlinkmember', "projectID=$project->id&account=$member->account"), $lang->project->unlinkMember, 'hiddenwin') . '';?> - - - - - - - - -
          team->account;?>team->role;?>team->join;?>team->days;?>team->hours;?>team->totalHours;?>
          - createLink('user', 'view', "account=$member->account"), $member->realname)) : print($member->realname); - $memberHours = $member->days * $member->hours; - $totalHours += $memberHours; - ?> - role;?>join, 2);?>days;?>hours;?>
          -
          team->totalHours . ':' . "$totalHours";?>
          -
          id", $lang->project->manageMembers);?>
          -
          - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + $lang->actions";?> + + + + + + + + + + + + + " . html::a($this->createLink('project', 'unlinkmember', "projectID=$project->id&account=$member->account"), $lang->project->unlinkMember, 'hiddenwin') . '';?> + + + + + + + + +
          team->account;?>team->role;?>team->join;?>team->days;?>team->hours;?>team->totalHours;?>
          + createLink('user', 'view', "account=$member->account"), $member->realname)) : print($member->realname); + $memberHours = $member->days * $member->hours; + $totalHours += $memberHours; + ?> + role;?>join, 2);?>days;?>hours;?>
          +
          team->totalHours . ':' . "$totalHours";?>
          +
          id", $lang->project->manageMembers);?>
          +
          + diff --git a/module/project/view/testtask.html.php b/module/project/view/testtask.html.php index 11e81c88a8..af10625d0c 100644 --- a/module/project/view/testtask.html.php +++ b/module/project/view/testtask.html.php @@ -1,54 +1,54 @@ - - * @package testtask - * @version $Id: browse.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          project->testtaskBrowse;?>
          -
          project->createTesttask);?>
          -
          idAB;?>testtask->name;?>testtask->build;?>testtask->owner;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          createLink('testtask', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>createLink('testtask', 'view', "taskID=$task->id"), $task->name);?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>owner];?>begin?>end?>testtask->statusList[$task->status];?> - id", $lang->testtask->cases); - common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); - common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); - common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); - ?> -
          - + + * @package testtask + * @version $Id: browse.html.php 1914 2011-06-24 10:11:25Z yidong@cnezsoft.com $ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          project->testtaskBrowse;?>
          +
          project->createTesttask);?>
          +
          idAB;?>testtask->name;?>testtask->build;?>testtask->owner;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          createLink('testtask', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>createLink('testtask', 'view', "taskID=$task->id"), $task->name);?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>owner];?>begin?>end?>testtask->statusList[$task->status];?> + id", $lang->testtask->cases); + common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); + common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); + common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); + ?> +
          + diff --git a/module/project/view/tips.html.php b/module/project/view/tips.html.php index 057e60ae6a..32889ce183 100644 --- a/module/project/view/tips.html.php +++ b/module/project/view/tips.html.php @@ -1,11 +1,11 @@ - - - - - -
          project->tips;?>
          project->afterInfo;?> -
          arrow. html::a($this->createLink('project', 'team', "projectID=$projectID"), $lang->project->setTeam);?>
          -
          arrow. html::a($this->createLink('project', 'linkstory', "projectID=$projectID"), $lang->project->linkStory);?>
          -
          arrow. html::a($this->createLink('task', 'create', "project=$projectID"), $lang->project->createTask);?>
          -
          arrow. html::a($this->createLink('project', 'task', "projectID=$projectID"), $lang->project->goback);?>
          -
          + + + + + +
          project->tips;?>
          project->afterInfo;?> +
          arrow. html::a($this->createLink('project', 'team', "projectID=$projectID"), $lang->project->setTeam);?>
          +
          arrow. html::a($this->createLink('project', 'linkstory', "projectID=$projectID"), $lang->project->linkStory);?>
          +
          arrow. html::a($this->createLink('task', 'create', "project=$projectID"), $lang->project->createTask);?>
          +
          arrow. html::a($this->createLink('project', 'task', "projectID=$projectID"), $lang->project->goback);?>
          +
          diff --git a/module/project/view/view.html.php b/module/project/view/view.html.php index d4b0240cf1..d0cfca257d 100644 --- a/module/project/view/view.html.php +++ b/module/project/view/view.html.php @@ -1,96 +1,96 @@ - - * @package project - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          name;?>
          project->name;?>'>name;?>
          project->code;?>code;?>
          project->beginAndEnd;?>begin . ' ~ ' . $project->end;?>
          project->days;?>days;?>
          project->goal;?>goal;?>
          project->desc;?>desc;?>
          project->status;?>show($lang->project->statusList, $project->status);?>
          project->PM;?>PM];?>
          project->PO;?>PO];?>
          project->QM;?>QM];?>
          project->RM;?>RM];?>
          project->lblStats;?>project->stats, $project->totalHours, $project->totalEstimate, $project->totalConsumed, $project->totalLeft, 10)?>
          project->products;?> - $productName) echo html::a($this->createLink('product', 'browse', "productID=$productID"), $productName) . '
          ';?> -
          project->acl;?>project->aclList[$project->acl];?>
          project->whitelist;?> - whitelist); - foreach($whitelist as $groupID) if(isset($groups[$groupID])) echo $groups[$groupID] . ' '; - ?> -
          -
          -session->projectList ? $this->session->projectList : inlink('task', "projectID=$project->id"); -if(!$project->deleted) -{ - common::printLink('project', 'edit', "projectID=$project->id", $lang->project->edit); - common::printLink('project', 'delete', "projectID=$project->id", $lang->project->delete, 'hiddenwin'); -} -echo html::a($browseLink, $lang->goback); -?> -
          - - + + * @package project + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          name;?>
          project->name;?>'>name;?>
          project->code;?>code;?>
          project->beginAndEnd;?>begin . ' ~ ' . $project->end;?>
          project->days;?>days;?>
          project->goal;?>goal;?>
          project->desc;?>desc;?>
          project->status;?>show($lang->project->statusList, $project->status);?>
          project->PM;?>PM];?>
          project->PO;?>PO];?>
          project->QM;?>QM];?>
          project->RM;?>RM];?>
          project->lblStats;?>project->stats, $project->totalHours, $project->totalEstimate, $project->totalConsumed, $project->totalLeft, 10)?>
          project->products;?> + $productName) echo html::a($this->createLink('product', 'browse', "productID=$productID"), $productName) . '
          ';?> +
          project->acl;?>project->aclList[$project->acl];?>
          project->whitelist;?> + whitelist); + foreach($whitelist as $groupID) if(isset($groups[$groupID])) echo $groups[$groupID] . ' '; + ?> +
          +
          +session->projectList ? $this->session->projectList : inlink('task', "projectID=$project->id"); +if(!$project->deleted) +{ + common::printLink('project', 'edit', "projectID=$project->id", $lang->project->edit); + common::printLink('project', 'delete', "projectID=$project->id", $lang->project->delete, 'hiddenwin'); +} +echo html::a($browseLink, $lang->goback); +?> +
          + + diff --git a/module/qa/control.php b/module/qa/control.php index a233144c15..2ddac19bb0 100644 --- a/module/qa/control.php +++ b/module/qa/control.php @@ -1,24 +1,24 @@ - - * @package qa - * @version $Id$ - * @link http://www.zentao.net - */ -class qa extends control -{ - /** - * The index of qa, go to bug's browse page. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('bug', 'browse')); - } -} + + * @package qa + * @version $Id$ + * @link http://www.zentao.net + */ +class qa extends control +{ + /** + * The index of qa, go to bug's browse page. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('bug', 'browse')); + } +} diff --git a/module/qa/lang/en.php b/module/qa/lang/en.php index e9061dc30d..60f80c5baf 100644 --- a/module/qa/lang/en.php +++ b/module/qa/lang/en.php @@ -1,13 +1,13 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->qa->common = 'Test'; -$lang->qa->index = "Index"; + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->qa->common = 'Test'; +$lang->qa->index = "Index"; diff --git a/module/qa/lang/zh-cn.php b/module/qa/lang/zh-cn.php index 0ea13ee4d9..815a69ed63 100644 --- a/module/qa/lang/zh-cn.php +++ b/module/qa/lang/zh-cn.php @@ -1,13 +1,13 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->qa->common = '测试视图'; -$lang->qa->index = "测试首页"; + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->qa->common = '测试视图'; +$lang->qa->index = "测试首页"; diff --git a/module/qa/lang/zh-tw.php b/module/qa/lang/zh-tw.php index 35d3df604d..160b8f9238 100644 --- a/module/qa/lang/zh-tw.php +++ b/module/qa/lang/zh-tw.php @@ -1,13 +1,13 @@ - - * @package company - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->qa->common = '測試視圖'; -$lang->qa->index = "測試首頁"; + + * @package company + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->qa->common = '測試視圖'; +$lang->qa->index = "測試首頁"; diff --git a/module/qa/model.php b/module/qa/model.php index fcf232038a..bdbbca25a5 100644 --- a/module/qa/model.php +++ b/module/qa/model.php @@ -1,15 +1,15 @@ - - * @package qa - * @version $Id$ - * @link http://www.zentao.net - */ -class qaModel extends model -{ -} - + + * @package qa + * @version $Id$ + * @link http://www.zentao.net + */ +class qaModel extends model +{ +} + diff --git a/module/qa/view/index.html.php b/module/qa/view/index.html.php index 72e1811063..5040042bbc 100644 --- a/module/qa/view/index.html.php +++ b/module/qa/view/index.html.php @@ -1,16 +1,16 @@ - - * @package company - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          - + + * @package company + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +
          + diff --git a/module/release/control.php b/module/release/control.php index 3ee2a3cd4b..8dadb1d743 100644 --- a/module/release/control.php +++ b/module/release/control.php @@ -1,194 +1,194 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -class release extends control -{ - /** - * Common actions. - * - * @param int $productID - * @access public - * @return void - */ - public function commonAction($productID) - { - $this->loadModel('product'); - $this->view->product = $this->product->getById($productID); - $this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name); - $this->product->setMenu($this->product->getPairs(), $productID); - } - - /** - * Browse releases. - * - * @param int $productID - * @access public - * @return void - */ - public function browse($productID) - { - $this->commonAction($productID); - $this->session->set('releaseList', $this->app->getURI(true)); - $this->view->header->title = $this->lang->release->browse; - $this->view->position[] = $this->lang->release->browse; - $this->view->releases = $this->release->getList($productID); - $this->display(); - } - - /** - * Create a release. - * - * @param int $productID - * @access public - * @return void - */ - public function create($productID) - { - if(!empty($_POST)) - { - $releaseID = $this->release->create($productID); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('release', $releaseID, 'opened'); - die(js::locate(inlink('view', "releaseID=$releaseID"), 'parent')); - } - - $builds = $this->loadModel('build')->getProductBuildPairs($productID); - unset($builds['trunk']); - - $this->commonAction($productID); - $this->view->header->title = $this->lang->release->create; - $this->view->position[] = $this->lang->release->create; - $this->view->builds = $builds; - $this->view->productID = $productID; - $this->display(); - } - - /** - * Edit a release. - * - * @param int $releaseID - * @access public - * @return void - */ - public function edit($releaseID) - { - if(!empty($_POST)) - { - $changes = $this->release->update($releaseID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('release', $releaseID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "releaseID=$releaseID"), 'parent')); - } - $this->loadModel('story'); - $this->loadModel('bug'); - $this->loadModel('project'); - $this->loadModel('build'); - - /* Get release and build. */ - $release = $this->release->getById((int)$releaseID); - $this->commonAction($release->product); - $build = $this->build->getById($release->build); - - /* Get stories and bugs. */ - $orderBy = 'status_asc, stage_asc, id_desc'; - $stories = $this->story->getProjectStories($build->project, $orderBy); - $bugs = $this->project->getResolvedBugs($build->project); - - $this->view->header->title = $this->lang->release->edit; - $this->view->position[] = $this->lang->release->edit; - $this->view->release = $release; - $this->view->build = $build; - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->builds = $this->loadModel('build')->getProductBuildPairs($release->product); - unset($this->view->builds['trunk']); - $this->display(); - } - - /** - * View a release. - * - * @param int $releaseID - * @access public - * @return void - */ - public function view($releaseID) - { - $this->loadModel('story'); - $this->loadModel('bug'); - $release = $this->release->getById((int)$releaseID); - if(!$release) die(js::error($this->lang->notFound) . js::locate('back')); - $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($release->stories)->fetchAll(); - $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->bugs)->fetchAll(); - - $this->commonAction($release->product); - - $this->view->header->title = $this->lang->release->view; - $this->view->position[] = $this->lang->release->view; - $this->view->release = $release; - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->actions = $this->loadModel('action')->getList('release', $releaseID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Delete a release. - * - * @param int $releaseID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($releaseID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->release->confirmDelete, $this->createLink('release', 'delete', "releaseID=$releaseID&confirm=yes"))); - } - else - { - $this->release->delete(TABLE_RELEASE, $releaseID); - die(js::locate($this->session->releaseList, 'parent')); - } - } - - /** - * Ajax get stories and bugs - * - * @param int $buildID - * @access public - * @return void - */ - public function ajaxGetStoriesAndBugs($buildID, $productID) - { - $orderBy = 'status_asc,stage_asc,id_desc'; - $stories = array(); - $bugs = array(); - $this->loadModel('bug'); - $build = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($buildID)->fetch(); - if(!empty($build)) - { - $stories = $this->loadModel('story')->getProjectStories($build->project, $orderBy); - $bugs = $this->loadModel('project')->getResolvedBugs($build->project); - } - $this->view->productID = $productID; - $this->view->stories = $stories; - $this->view->bugs = $bugs; - $this->view->orderBy = $orderBy; - die($this->display()); - } -} + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +class release extends control +{ + /** + * Common actions. + * + * @param int $productID + * @access public + * @return void + */ + public function commonAction($productID) + { + $this->loadModel('product'); + $this->view->product = $this->product->getById($productID); + $this->view->position[] = html::a($this->createLink('product', 'browse', "productID={$this->view->product->id}"), $this->view->product->name); + $this->product->setMenu($this->product->getPairs(), $productID); + } + + /** + * Browse releases. + * + * @param int $productID + * @access public + * @return void + */ + public function browse($productID) + { + $this->commonAction($productID); + $this->session->set('releaseList', $this->app->getURI(true)); + $this->view->header->title = $this->lang->release->browse; + $this->view->position[] = $this->lang->release->browse; + $this->view->releases = $this->release->getList($productID); + $this->display(); + } + + /** + * Create a release. + * + * @param int $productID + * @access public + * @return void + */ + public function create($productID) + { + if(!empty($_POST)) + { + $releaseID = $this->release->create($productID); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('release', $releaseID, 'opened'); + die(js::locate(inlink('view', "releaseID=$releaseID"), 'parent')); + } + + $builds = $this->loadModel('build')->getProductBuildPairs($productID); + unset($builds['trunk']); + + $this->commonAction($productID); + $this->view->header->title = $this->lang->release->create; + $this->view->position[] = $this->lang->release->create; + $this->view->builds = $builds; + $this->view->productID = $productID; + $this->display(); + } + + /** + * Edit a release. + * + * @param int $releaseID + * @access public + * @return void + */ + public function edit($releaseID) + { + if(!empty($_POST)) + { + $changes = $this->release->update($releaseID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('release', $releaseID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "releaseID=$releaseID"), 'parent')); + } + $this->loadModel('story'); + $this->loadModel('bug'); + $this->loadModel('project'); + $this->loadModel('build'); + + /* Get release and build. */ + $release = $this->release->getById((int)$releaseID); + $this->commonAction($release->product); + $build = $this->build->getById($release->build); + + /* Get stories and bugs. */ + $orderBy = 'status_asc, stage_asc, id_desc'; + $stories = $this->story->getProjectStories($build->project, $orderBy); + $bugs = $this->project->getResolvedBugs($build->project); + + $this->view->header->title = $this->lang->release->edit; + $this->view->position[] = $this->lang->release->edit; + $this->view->release = $release; + $this->view->build = $build; + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($release->product); + unset($this->view->builds['trunk']); + $this->display(); + } + + /** + * View a release. + * + * @param int $releaseID + * @access public + * @return void + */ + public function view($releaseID) + { + $this->loadModel('story'); + $this->loadModel('bug'); + $release = $this->release->getById((int)$releaseID); + if(!$release) die(js::error($this->lang->notFound) . js::locate('back')); + $stories = $this->dao->select('*')->from(TABLE_STORY)->where('id')->in($release->stories)->fetchAll(); + $bugs = $this->dao->select('*')->from(TABLE_BUG)->where('id')->in($release->bugs)->fetchAll(); + + $this->commonAction($release->product); + + $this->view->header->title = $this->lang->release->view; + $this->view->position[] = $this->lang->release->view; + $this->view->release = $release; + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->actions = $this->loadModel('action')->getList('release', $releaseID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Delete a release. + * + * @param int $releaseID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($releaseID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->release->confirmDelete, $this->createLink('release', 'delete', "releaseID=$releaseID&confirm=yes"))); + } + else + { + $this->release->delete(TABLE_RELEASE, $releaseID); + die(js::locate($this->session->releaseList, 'parent')); + } + } + + /** + * Ajax get stories and bugs + * + * @param int $buildID + * @access public + * @return void + */ + public function ajaxGetStoriesAndBugs($buildID, $productID) + { + $orderBy = 'status_asc,stage_asc,id_desc'; + $stories = array(); + $bugs = array(); + $this->loadModel('bug'); + $build = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($buildID)->fetch(); + if(!empty($build)) + { + $stories = $this->loadModel('story')->getProjectStories($build->project, $orderBy); + $bugs = $this->loadModel('project')->getResolvedBugs($build->project); + } + $this->view->productID = $productID; + $this->view->stories = $stories; + $this->view->bugs = $bugs; + $this->view->orderBy = $orderBy; + die($this->display()); + } +} diff --git a/module/release/lang/en.php b/module/release/lang/en.php index a39e02408c..a247fbb51b 100644 --- a/module/release/lang/en.php +++ b/module/release/lang/en.php @@ -1,32 +1,32 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->release->common = 'Release'; -$lang->release->create = "Create"; -$lang->release->edit = "Edit"; -$lang->release->delete = "Delete"; -$lang->release->view = "Info"; -$lang->release->browse = "Browse"; - -$lang->release->confirmDelete = "Are sure to delete this release?"; - -$lang->release->id = 'ID'; -$lang->release->product = 'Product'; -$lang->release->build = 'Build'; -$lang->release->name = 'Name'; -$lang->release->date = 'Date'; -$lang->release->desc = 'Desc'; -$lang->release->linkStoriesAndBugs = 'Stories and bugs'; -$lang->release->linkStories = 'Stories'; -$lang->release->linkBugs = 'Bugs'; -$lang->release->stories = 'Linked stories'; -$lang->release->bugs = 'Linked bugs'; -$lang->release->ajaxGetStoriesAndBugs = 'API: Get storeis and bugs'; + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->release->common = 'Release'; +$lang->release->create = "Create"; +$lang->release->edit = "Edit"; +$lang->release->delete = "Delete"; +$lang->release->view = "Info"; +$lang->release->browse = "Browse"; + +$lang->release->confirmDelete = "Are sure to delete this release?"; + +$lang->release->id = 'ID'; +$lang->release->product = 'Product'; +$lang->release->build = 'Build'; +$lang->release->name = 'Name'; +$lang->release->date = 'Date'; +$lang->release->desc = 'Desc'; +$lang->release->linkStoriesAndBugs = 'Stories and bugs'; +$lang->release->linkStories = 'Stories'; +$lang->release->linkBugs = 'Bugs'; +$lang->release->stories = 'Linked stories'; +$lang->release->bugs = 'Linked bugs'; +$lang->release->ajaxGetStoriesAndBugs = 'API: Get storeis and bugs'; diff --git a/module/release/lang/zh-cn.php b/module/release/lang/zh-cn.php index 40d2d4dc7b..4bb5ba3282 100644 --- a/module/release/lang/zh-cn.php +++ b/module/release/lang/zh-cn.php @@ -1,32 +1,32 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->release->common = '发布'; -$lang->release->create = "创建发布"; -$lang->release->edit = "编辑发布"; -$lang->release->delete = "删除发布"; -$lang->release->view = "发布详情"; -$lang->release->browse = "浏览发布"; - -$lang->release->confirmDelete = "您确认删除该release吗?"; - -$lang->release->id = 'ID'; -$lang->release->product = '产品'; -$lang->release->build = 'Build'; -$lang->release->name = '发布名称'; -$lang->release->date = '发布日期'; -$lang->release->desc = '描述'; -$lang->release->linkStoriesAndBugs = '需求和Bug'; -$lang->release->linkStories = '相关需求'; -$lang->release->linkBugs = '相关Bug'; -$lang->release->stories = '已关联需求'; -$lang->release->bugs = '已关联Bugs'; -$lang->release->ajaxGetStoriesAndBugs = '接口:获得需求和Bug'; + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->release->common = '发布'; +$lang->release->create = "创建发布"; +$lang->release->edit = "编辑发布"; +$lang->release->delete = "删除发布"; +$lang->release->view = "发布详情"; +$lang->release->browse = "浏览发布"; + +$lang->release->confirmDelete = "您确认删除该release吗?"; + +$lang->release->id = 'ID'; +$lang->release->product = '产品'; +$lang->release->build = 'Build'; +$lang->release->name = '发布名称'; +$lang->release->date = '发布日期'; +$lang->release->desc = '描述'; +$lang->release->linkStoriesAndBugs = '需求和Bug'; +$lang->release->linkStories = '相关需求'; +$lang->release->linkBugs = '相关Bug'; +$lang->release->stories = '已关联需求'; +$lang->release->bugs = '已关联Bugs'; +$lang->release->ajaxGetStoriesAndBugs = '接口:获得需求和Bug'; diff --git a/module/release/lang/zh-tw.php b/module/release/lang/zh-tw.php index 901e11c4aa..3b650ab2e5 100644 --- a/module/release/lang/zh-tw.php +++ b/module/release/lang/zh-tw.php @@ -1,32 +1,32 @@ - - * @package release - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->release->common = '發佈'; -$lang->release->create = "創建發佈"; -$lang->release->edit = "編輯發佈"; -$lang->release->delete = "刪除發佈"; -$lang->release->view = "發佈詳情"; -$lang->release->browse = "瀏覽發佈"; - -$lang->release->confirmDelete = "您確認刪除該release嗎?"; - -$lang->release->id = 'ID'; -$lang->release->product = '產品'; -$lang->release->build = 'Build'; -$lang->release->name = '發佈名稱'; -$lang->release->date = '發佈日期'; -$lang->release->desc = '描述'; -$lang->release->linkStoriesAndBugs = '需求和Bug'; -$lang->release->linkStories = '相關需求'; -$lang->release->linkBugs = '相關Bug'; -$lang->release->stories = '已關聯需求'; -$lang->release->bugs = '已關聯Bugs'; -$lang->release->ajaxGetStoriesAndBugs = '介面:獲得需求和Bug'; + + * @package release + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->release->common = '發佈'; +$lang->release->create = "創建發佈"; +$lang->release->edit = "編輯發佈"; +$lang->release->delete = "刪除發佈"; +$lang->release->view = "發佈詳情"; +$lang->release->browse = "瀏覽發佈"; + +$lang->release->confirmDelete = "您確認刪除該release嗎?"; + +$lang->release->id = 'ID'; +$lang->release->product = '產品'; +$lang->release->build = 'Build'; +$lang->release->name = '發佈名稱'; +$lang->release->date = '發佈日期'; +$lang->release->desc = '描述'; +$lang->release->linkStoriesAndBugs = '需求和Bug'; +$lang->release->linkStories = '相關需求'; +$lang->release->linkBugs = '相關Bug'; +$lang->release->stories = '已關聯需求'; +$lang->release->bugs = '已關聯Bugs'; +$lang->release->ajaxGetStoriesAndBugs = '介面:獲得需求和Bug'; diff --git a/module/release/model.php b/module/release/model.php index b407d4db24..b03737f3a0 100644 --- a/module/release/model.php +++ b/module/release/model.php @@ -1,102 +1,102 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->select('t1.*, t2.name as buildName, t3.name as productName') - ->from(TABLE_RELEASE)->alias('t1') - ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.build = t2.id') - ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') - ->where('t1.id')->eq((int)$releaseID) - ->orderBy('t1.id DESC') - ->fetch(); - $release->desc = $this->loadModel('file')->setImgSize($release->desc); - return $release; - } - - /** - * Get list of releases. - * - * @param int $productID - * @access public - * @return array - */ - public function getList($productID) - { - return $this->dao->select('t1.*, t2.name as productName, t3.name as buildName') - ->from(TABLE_RELEASE)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') - ->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id') - ->where('t1.product')->eq((int)$productID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy('t1.date DESC') - ->fetchAll(); - } - - /** - * Create a release. - * - * @param int $productID - * @access public - * @return int - */ - public function create($productID) - { - $release = fixer::input('post') - ->stripTags('name') - ->add('product', (int)$productID) - ->join('stories', ',') - ->join('bugs', ',') - ->get(); - $this->dao->insert(TABLE_RELEASE)->data($release)->autoCheck()->batchCheck($this->config->release->create->requiredFields, 'notempty')->check('name','unique')->exec(); - $releaseID = $this->dao->lastInsertID(); - $this->dao->update(TABLE_STORY)->set('stage')->eq('released')->where('id')->in($release->stories)->exec(); - if(!dao::isError()) return $releaseID; - } - - /** - * Update a release. - * - * @param int $releaseID - * @access public - * @return void - */ - public function update($releaseID) - { - $oldRelease = $this->getByID($releaseID); - $release = fixer::input('post') - ->stripTags('name') - ->setDefault('stories', '') - ->setDefault('bugs', '') - ->join('stories', ',') - ->join('bugs', ',') - ->get(); - $this->dao->update(TABLE_RELEASE)->data($release) - ->autoCheck() - ->batchCheck($this->config->release->edit->requiredFields, 'notempty') - ->check('name','unique', "id != $releaseID") - ->where('id')->eq((int)$releaseID) - ->exec(); - $this->dao->update(TABLE_STORY)->set('stage')->eq('released')->where('id')->in($release->stories)->exec(); - if(!dao::isError()) return common::createChanges($oldRelease, $release); - } -} + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->select('t1.*, t2.name as buildName, t3.name as productName') + ->from(TABLE_RELEASE)->alias('t1') + ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.build = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.id')->eq((int)$releaseID) + ->orderBy('t1.id DESC') + ->fetch(); + $release->desc = $this->loadModel('file')->setImgSize($release->desc); + return $release; + } + + /** + * Get list of releases. + * + * @param int $productID + * @access public + * @return array + */ + public function getList($productID) + { + return $this->dao->select('t1.*, t2.name as productName, t3.name as buildName') + ->from(TABLE_RELEASE)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') + ->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id') + ->where('t1.product')->eq((int)$productID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('t1.date DESC') + ->fetchAll(); + } + + /** + * Create a release. + * + * @param int $productID + * @access public + * @return int + */ + public function create($productID) + { + $release = fixer::input('post') + ->stripTags('name') + ->add('product', (int)$productID) + ->join('stories', ',') + ->join('bugs', ',') + ->get(); + $this->dao->insert(TABLE_RELEASE)->data($release)->autoCheck()->batchCheck($this->config->release->create->requiredFields, 'notempty')->check('name','unique')->exec(); + $releaseID = $this->dao->lastInsertID(); + $this->dao->update(TABLE_STORY)->set('stage')->eq('released')->where('id')->in($release->stories)->exec(); + if(!dao::isError()) return $releaseID; + } + + /** + * Update a release. + * + * @param int $releaseID + * @access public + * @return void + */ + public function update($releaseID) + { + $oldRelease = $this->getByID($releaseID); + $release = fixer::input('post') + ->stripTags('name') + ->setDefault('stories', '') + ->setDefault('bugs', '') + ->join('stories', ',') + ->join('bugs', ',') + ->get(); + $this->dao->update(TABLE_RELEASE)->data($release) + ->autoCheck() + ->batchCheck($this->config->release->edit->requiredFields, 'notempty') + ->check('name','unique', "id != $releaseID") + ->where('id')->eq((int)$releaseID) + ->exec(); + $this->dao->update(TABLE_STORY)->set('stage')->eq('released')->where('id')->in($release->stories)->exec(); + if(!dao::isError()) return common::createChanges($oldRelease, $release); + } +} diff --git a/module/release/view/browse.html.php b/module/release/view/browse.html.php index 3cd0d5d184..fbb8459b7e 100644 --- a/module/release/view/browse.html.php +++ b/module/release/view/browse.html.php @@ -1,46 +1,46 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          release->browse;?>
          -
          id", $lang->release->create);?>
          -
          release->id;?>release->name;?>release->build;?>release->date;?>actions;?>
          id;?>id"), $release->name);?>buildName;?>date;?> - id", $lang->edit); - common::printLink('release', 'delete', "release=$release->id", $lang->delete, 'hiddenwin'); - ?> -
          - + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          release->browse;?>
          +
          id", $lang->release->create);?>
          +
          release->id;?>release->name;?>release->build;?>release->date;?>actions;?>
          id;?>id"), $release->name);?>buildName;?>date;?> + id", $lang->edit); + common::printLink('release', 'delete', "release=$release->id", $lang->delete, 'hiddenwin'); + ?> +
          + diff --git a/module/release/view/create.html.php b/module/release/view/create.html.php index af90bc7667..a72c8cd675 100644 --- a/module/release/view/create.html.php +++ b/module/release/view/create.html.php @@ -1,40 +1,40 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - -
          release->create;?>
          release->name;?>
          release->build;?>
          release->date;?>
          release->desc;?>
          -
          - + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + +
          release->create;?>
          release->name;?>
          release->build;?>
          release->date;?>
          release->desc;?>
          +
          + diff --git a/module/release/view/edit.html.php b/module/release/view/edit.html.php index c829c30631..2f07a838b5 100644 --- a/module/release/view/edit.html.php +++ b/module/release/view/edit.html.php @@ -1,87 +1,87 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - -
          release->edit;?>
          release->name;?>name, "class='text-3'");?>
          release->build;?>build, "class='select-3' onchange=loadStoriesAndBugs(this.value,$release->product)"); ?>
          release->date;?>date, "class='text-3 date'");?>
          release->linkStoriesAndBugs;?> -
          -
          - - - - - - - - - $story):?> - createLink('story', 'view', "storyID=$story->id"); - ?> - - - - - - - -
          release->linkStories;?>
          idAB;?>story->title;?>statusAB;?>story->stageAB;?>
          stories, $story->id) !== false) echo 'checked';?>> id);?>title, '', "class='preview'");?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
          -
          -
          - - - - - - - - - createLink('bug', 'view', "bugID=$bug->id");?> - - - - - - -
          release->linkBugs;?>
          idAB;?>bug->title;?>bug->status;?>
          bugs, $bug->id) !== false) echo 'checked';?>> id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>
          -
          -
          -
          release->desc;?>desc), "rows='20' class='area-1'");?>
          product);?>
          -
          - + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + +
          release->edit;?>
          release->name;?>name, "class='text-3'");?>
          release->build;?>build, "class='select-3' onchange=loadStoriesAndBugs(this.value,$release->product)"); ?>
          release->date;?>date, "class='text-3 date'");?>
          release->linkStoriesAndBugs;?> +
          +
          + + + + + + + + + $story):?> + createLink('story', 'view', "storyID=$story->id"); + ?> + + + + + + + +
          release->linkStories;?>
          idAB;?>story->title;?>statusAB;?>story->stageAB;?>
          stories, $story->id) !== false) echo 'checked';?>> id);?>title, '', "class='preview'");?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
          +
          +
          + + + + + + + + + createLink('bug', 'view', "bugID=$bug->id");?> + + + + + + +
          release->linkBugs;?>
          idAB;?>bug->title;?>bug->status;?>
          bugs, $bug->id) !== false) echo 'checked';?>> id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>
          +
          +
          +
          release->desc;?>desc), "rows='20' class='area-1'");?>
          product);?>
          +
          + diff --git a/module/release/view/view.html.php b/module/release/view/view.html.php index 42277f4ac8..bd150dd632 100644 --- a/module/release/view/view.html.php +++ b/module/release/view/view.html.php @@ -1,109 +1,109 @@ - - * @package release - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          release->view;?>
          release->product;?>productName;?>
          release->name;?>'>name;?>
          release->build;?>buildName;?>
          release->date;?>date;?>
          release->stories;?> -
          - - - - - - - - - - - $story):?> - createLink('story', 'view', "storyID=$story->id");?> - - - - - - - - - - -
          idAB;?>priAB;?>story->title;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>
          id);?>story->priList[$story->pri];?>title, '', "class='preview'");?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
          -
          -
          release->bugs;?> -
          - - - - - - - - - - - - createLink('bug', 'view', "bugID=$bug->id");?> - - - - - - - - - - -
          idAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?>
          id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>openedBy];?>openedDate, 5, 11)?>resolvedBy];?>resolvedDate, 5, 11)?>
          -
          -
          release->desc;?>desc;?>
          -
          - session->releaseList ? $this->session->releaseList : inlink('browse', "productID=$release->product"); - if(!$release->deleted) - { - common::printLink('release', 'edit', "releaseID=$release->id", $lang->edit); - common::printLink('release', 'delete', "releaseID=$release->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - - + + * @package release + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          release->view;?>
          release->product;?>productName;?>
          release->name;?>'>name;?>
          release->build;?>buildName;?>
          release->date;?>date;?>
          release->stories;?> +
          + + + + + + + + + + + $story):?> + createLink('story', 'view', "storyID=$story->id");?> + + + + + + + + + + +
          idAB;?>priAB;?>story->title;?>openedByAB;?>story->estimateAB;?>statusAB;?>story->stageAB;?>
          id);?>story->priList[$story->pri];?>title, '', "class='preview'");?>openedBy];?>estimate;?>story->statusList[$story->status];?>story->stageList[$story->stage];?>
          +
          +
          release->bugs;?> +
          + + + + + + + + + + + + createLink('bug', 'view', "bugID=$bug->id");?> + + + + + + + + + + +
          idAB;?>bug->title;?>bug->status;?>openedByAB;?>bug->openedDateAB;?>bug->resolvedByAB;?>bug->resolvedDateAB;?>
          id);?>title, '', "class='preview'");?>bug->statusList[$bug->status];?>openedBy];?>openedDate, 5, 11)?>resolvedBy];?>resolvedDate, 5, 11)?>
          +
          +
          release->desc;?>desc;?>
          +
          + session->releaseList ? $this->session->releaseList : inlink('browse', "productID=$release->product"); + if(!$release->deleted) + { + common::printLink('release', 'edit', "releaseID=$release->id", $lang->edit); + common::printLink('release', 'delete', "releaseID=$release->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + + diff --git a/module/report/control.php b/module/report/control.php index 03371fab93..9a3c3f3594 100644 --- a/module/report/control.php +++ b/module/report/control.php @@ -1,14 +1,14 @@ - - * @package report - * @version $Id$ - * @link http://www.zentao.net - */ -class report extends control -{ -} + + * @package report + * @version $Id$ + * @link http://www.zentao.net + */ +class report extends control +{ +} diff --git a/module/report/lang/en.php b/module/report/lang/en.php index f0c71a480c..9d3bbd80e1 100644 --- a/module/report/lang/en.php +++ b/module/report/lang/en.php @@ -1,31 +1,31 @@ - - * @package report - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->report->common = 'Report'; -$lang->report->item = 'Item'; -$lang->report->value = 'Value'; -$lang->report->percent = 'Percent'; -$lang->report->undefined = 'Undefined'; - -$lang->report->colors[] = 'AFD8F8'; -$lang->report->colors[] = 'F6BD0F'; -$lang->report->colors[] = '8BBA00'; -$lang->report->colors[] = 'FF8E46'; -$lang->report->colors[] = '008E8E'; -$lang->report->colors[] = 'D64646'; -$lang->report->colors[] = '8E468E'; -$lang->report->colors[] = '588526'; -$lang->report->colors[] = 'B3AA00'; -$lang->report->colors[] = '008ED6'; -$lang->report->colors[] = '9D080D'; -$lang->report->colors[] = 'A186BE'; - -$lang->report->singleColor[] = 'F6BD0F'; + + * @package report + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->report->common = 'Report'; +$lang->report->item = 'Item'; +$lang->report->value = 'Value'; +$lang->report->percent = 'Percent'; +$lang->report->undefined = 'Undefined'; + +$lang->report->colors[] = 'AFD8F8'; +$lang->report->colors[] = 'F6BD0F'; +$lang->report->colors[] = '8BBA00'; +$lang->report->colors[] = 'FF8E46'; +$lang->report->colors[] = '008E8E'; +$lang->report->colors[] = 'D64646'; +$lang->report->colors[] = '8E468E'; +$lang->report->colors[] = '588526'; +$lang->report->colors[] = 'B3AA00'; +$lang->report->colors[] = '008ED6'; +$lang->report->colors[] = '9D080D'; +$lang->report->colors[] = 'A186BE'; + +$lang->report->singleColor[] = 'F6BD0F'; diff --git a/module/report/lang/zh-cn.php b/module/report/lang/zh-cn.php index 2fb2dc0fcc..97ae65e97b 100644 --- a/module/report/lang/zh-cn.php +++ b/module/report/lang/zh-cn.php @@ -1,31 +1,31 @@ - - * @package report - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->report->common = '报表'; -$lang->report->item = '条目'; -$lang->report->value = '值'; -$lang->report->percent = '百分比'; -$lang->report->undefined = '未设定'; - -$lang->report->colors[] = 'AFD8F8'; -$lang->report->colors[] = 'F6BD0F'; -$lang->report->colors[] = '8BBA00'; -$lang->report->colors[] = 'FF8E46'; -$lang->report->colors[] = '008E8E'; -$lang->report->colors[] = 'D64646'; -$lang->report->colors[] = '8E468E'; -$lang->report->colors[] = '588526'; -$lang->report->colors[] = 'B3AA00'; -$lang->report->colors[] = '008ED6'; -$lang->report->colors[] = '9D080D'; -$lang->report->colors[] = 'A186BE'; - -$lang->report->singleColor[] = 'F6BD0F'; + + * @package report + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->report->common = '报表'; +$lang->report->item = '条目'; +$lang->report->value = '值'; +$lang->report->percent = '百分比'; +$lang->report->undefined = '未设定'; + +$lang->report->colors[] = 'AFD8F8'; +$lang->report->colors[] = 'F6BD0F'; +$lang->report->colors[] = '8BBA00'; +$lang->report->colors[] = 'FF8E46'; +$lang->report->colors[] = '008E8E'; +$lang->report->colors[] = 'D64646'; +$lang->report->colors[] = '8E468E'; +$lang->report->colors[] = '588526'; +$lang->report->colors[] = 'B3AA00'; +$lang->report->colors[] = '008ED6'; +$lang->report->colors[] = '9D080D'; +$lang->report->colors[] = 'A186BE'; + +$lang->report->singleColor[] = 'F6BD0F'; diff --git a/module/report/lang/zh-tw.php b/module/report/lang/zh-tw.php index f8a214ebed..287fa8a0c3 100644 --- a/module/report/lang/zh-tw.php +++ b/module/report/lang/zh-tw.php @@ -1,31 +1,31 @@ - - * @package report - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->report->common = '報表'; -$lang->report->item = '條目'; -$lang->report->value = '值'; -$lang->report->percent = '百分比'; -$lang->report->undefined = '未設定'; - -$lang->report->colors[] = 'AFD8F8'; -$lang->report->colors[] = 'F6BD0F'; -$lang->report->colors[] = '8BBA00'; -$lang->report->colors[] = 'FF8E46'; -$lang->report->colors[] = '008E8E'; -$lang->report->colors[] = 'D64646'; -$lang->report->colors[] = '8E468E'; -$lang->report->colors[] = '588526'; -$lang->report->colors[] = 'B3AA00'; -$lang->report->colors[] = '008ED6'; -$lang->report->colors[] = '9D080D'; -$lang->report->colors[] = 'A186BE'; - -$lang->report->singleColor[] = 'F6BD0F'; + + * @package report + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->report->common = '報表'; +$lang->report->item = '條目'; +$lang->report->value = '值'; +$lang->report->percent = '百分比'; +$lang->report->undefined = '未設定'; + +$lang->report->colors[] = 'AFD8F8'; +$lang->report->colors[] = 'F6BD0F'; +$lang->report->colors[] = '8BBA00'; +$lang->report->colors[] = 'FF8E46'; +$lang->report->colors[] = '008E8E'; +$lang->report->colors[] = 'D64646'; +$lang->report->colors[] = '8E468E'; +$lang->report->colors[] = '588526'; +$lang->report->colors[] = 'B3AA00'; +$lang->report->colors[] = '008ED6'; +$lang->report->colors[] = '9D080D'; +$lang->report->colors[] = 'A186BE'; + +$lang->report->singleColor[] = 'F6BD0F'; diff --git a/module/report/model.php b/module/report/model.php index 72584be0f6..2d47f94a1d 100644 --- a/module/report/model.php +++ b/module/report/model.php @@ -1,231 +1,231 @@ - - * @package report - * @version $Id$ - * @link http://www.zentao.net - */ -?> -app->getWebRoot() . 'fusioncharts/'; - $swfFile = "fcf_$swf.swf"; - return << - - - - - - -EOT; - } - - /** - * Create the js code of chart. - * - * @param string $swf the swf type - * @param string $dataURL the date url - * @param int $width - * @param int $height - * @access public - * @return string - */ - public function createJSChart($swf, $dataXML, $width = 'auto', $height = 500) - { - $jsRoot = $this->app->getWebRoot() . 'js/'; - static $count = 0; - $count ++; - $chartRoot = $this->app->getWebRoot() . 'fusioncharts/'; - $swfFile = "fcf_$swf.swf"; - $divID = "chart{$count}div"; - $chartID = "chart{$count}"; - - $js = ''; - if($count == 1) $js = ""; - return << - -EOT; - } - - public function createJSChartFlot($projectName, $dataJSON, $count, $width = 'auto', $height = 500) - { - $this->app->loadLang('project'); - $jsRoot = $this->app->getWebRoot() . 'js/'; - $width = $width . 'px'; - $height = $height . 'px'; -return << - -

          $projectName {$this->lang->project->burn}

          -
          - -EOT; - } - - /** - * Create xml data of single charts. - * - * @param array $sets - * @param array $chartOptions - * @param array $colors - * @access public - * @return string the xml data. - */ - public function createSingleXML($sets, $chartOptions = array(), $colors = array()) - { - $data = pack("CCC", 0xef, 0xbb, 0xbf); // utf-8 bom. - $data .=""; - - $data .= ' $value) $data .= " $key='$value'"; - $data .= ">"; - - if(empty($colors)) $colors = $this->lang->report->colors; - $colorCount = count($colors); - $i = 0; - foreach($sets as $set) - { - if($i == $colorCount) $i = 0; - $color = $colors[$i]; - $i ++; - $data .= ""; - } - $data .= ""; - return $data; - } - - public function createSingleJSON($sets) - { - $data = '['; - foreach($sets as $set) - { - $data .= " [$set->name, $set->value],"; - } - $data = rtrim($data, ','); - $data .= ']'; - return $data; - } - - /** - * Create the js code to render chart. - * - * @param int $chartCount - * @access public - * @return string - */ - public function renderJsCharts($chartCount) - { - $js = ''; - return $js; - } - - /** - * Compute percent of every item. - * - * @param array $datas - * @access public - * @return array - */ - public function computePercent($datas) - { - $sum = 0; - foreach($datas as $data) $sum += $data->value; - foreach($datas as $data) $data->percent = round($data->value / $sum, 2); - return $datas; - } -} + + * @package report + * @version $Id$ + * @link http://www.zentao.net + */ +?> +app->getWebRoot() . 'fusioncharts/'; + $swfFile = "fcf_$swf.swf"; + return << + + + + + + +EOT; + } + + /** + * Create the js code of chart. + * + * @param string $swf the swf type + * @param string $dataURL the date url + * @param int $width + * @param int $height + * @access public + * @return string + */ + public function createJSChart($swf, $dataXML, $width = 'auto', $height = 500) + { + $jsRoot = $this->app->getWebRoot() . 'js/'; + static $count = 0; + $count ++; + $chartRoot = $this->app->getWebRoot() . 'fusioncharts/'; + $swfFile = "fcf_$swf.swf"; + $divID = "chart{$count}div"; + $chartID = "chart{$count}"; + + $js = ''; + if($count == 1) $js = ""; + return << + +EOT; + } + + public function createJSChartFlot($projectName, $dataJSON, $count, $width = 'auto', $height = 500) + { + $this->app->loadLang('project'); + $jsRoot = $this->app->getWebRoot() . 'js/'; + $width = $width . 'px'; + $height = $height . 'px'; +return << + +

          $projectName {$this->lang->project->burn}

          +
          + +EOT; + } + + /** + * Create xml data of single charts. + * + * @param array $sets + * @param array $chartOptions + * @param array $colors + * @access public + * @return string the xml data. + */ + public function createSingleXML($sets, $chartOptions = array(), $colors = array()) + { + $data = pack("CCC", 0xef, 0xbb, 0xbf); // utf-8 bom. + $data .=""; + + $data .= ' $value) $data .= " $key='$value'"; + $data .= ">"; + + if(empty($colors)) $colors = $this->lang->report->colors; + $colorCount = count($colors); + $i = 0; + foreach($sets as $set) + { + if($i == $colorCount) $i = 0; + $color = $colors[$i]; + $i ++; + $data .= ""; + } + $data .= ""; + return $data; + } + + public function createSingleJSON($sets) + { + $data = '['; + foreach($sets as $set) + { + $data .= " [$set->name, $set->value],"; + } + $data = rtrim($data, ','); + $data .= ']'; + return $data; + } + + /** + * Create the js code to render chart. + * + * @param int $chartCount + * @access public + * @return string + */ + public function renderJsCharts($chartCount) + { + $js = ''; + return $js; + } + + /** + * Compute percent of every item. + * + * @param array $datas + * @access public + * @return array + */ + public function computePercent($datas) + { + $sum = 0; + foreach($datas as $data) $sum += $data->value; + foreach($datas as $data) $data->percent = round($data->value / $sum, 2); + return $datas; + } +} diff --git a/module/search/control.php b/module/search/control.php index 90992be7f5..0d88502589 100644 --- a/module/search/control.php +++ b/module/search/control.php @@ -1,116 +1,116 @@ - - * @package search - * @version $Id$ - * @link http://www.zentao.net - */ -class search extends control -{ - /** - * Build search form. - * - * @param string $module - * @param array $searchFields - * @param array $fieldParams - * @param string $actionURL - * @param int $queryID - * @access public - * @return void - */ - public function buildForm($module, $searchFields, $fieldParams, $actionURL, $queryID = 0) - { - $this->search->initSession($module, $searchFields, $fieldParams); - - $this->view->module = $module; - $this->view->groupItems = $this->config->search->groupItems; - $this->view->searchFields = $searchFields; - $this->view->actionURL = $actionURL; - $this->view->fieldParams = $this->search->setDefaultParams($searchFields, $fieldParams); - $this->view->queries = $this->search->getQueryPairs($module); - $this->view->queryID = $queryID; - $this->display(); - } - - /** - * Build query - * - * @access public - * @return void - */ - public function buildQuery() - { - $this->search->buildQuery(); - die(js::locate($this->post->actionURL, 'parent')); - } - - /** - * Save search query. - * - * @access public - * @return void - */ - public function saveQuery() - { - $this->search->saveQuery(); - if(dao::isError()) die(js::error(dao::getError())); - die('success'); - } - - /** - * Delete a query - * - * @param int $queryID - * @access public - * @return void - */ - public function deleteQuery($queryID) - { - $this->dao->delete()->from(TABLE_USERQUERY)->where('id')->eq($queryID)->andWhere('account')->eq($this->app->user->account)->exec(); - die(js::reload('parent')); - } - - /** - * Create a select page of stories or tasks. - * - * @param int $productID - * @param int $projectID - * @param string $module - * @param int $moduleID - * @access public - * @return void - */ - public function select($productID, $projectID, $module, $moduleID) - { - $this->loadModel('product'); - $this->loadModel('task'); - - if($module == 'story') - { - $fieldParams = $this->config->product->search; - $moduleTitles = $projectID ? $this->loadModel('story')->getProjectStoryPairs($projectID, $productID) : $this->loadModel('story')->getProductStoryPairs($productID); - } - else if($module == 'task') - { - $fieldParams = $this->config->task->search; - $moduleTitles = $this->loadModel('task')->getProjectTaskPairs($projectID); - } - $searchFields = $fieldParams['fields']; - $fieldParams = $fieldParams['params']; - $this->search->initSession($module, $searchFields, $fieldParams); - - if(!empty($_POST['value1'])) $moduleTitles = $this->search->getBySelect($module, array_keys($moduleTitles), $_POST); - - $this->view->module = $module; - $this->view->moduleID = $moduleID; - $this->view->moduleTitles = $moduleTitles; - $this->view->searchFields = $searchFields; - $this->view->fieldParams = $this->search->setDefaultParams($searchFields, $fieldParams); - - die($this->display()); - } -} + + * @package search + * @version $Id$ + * @link http://www.zentao.net + */ +class search extends control +{ + /** + * Build search form. + * + * @param string $module + * @param array $searchFields + * @param array $fieldParams + * @param string $actionURL + * @param int $queryID + * @access public + * @return void + */ + public function buildForm($module, $searchFields, $fieldParams, $actionURL, $queryID = 0) + { + $this->search->initSession($module, $searchFields, $fieldParams); + + $this->view->module = $module; + $this->view->groupItems = $this->config->search->groupItems; + $this->view->searchFields = $searchFields; + $this->view->actionURL = $actionURL; + $this->view->fieldParams = $this->search->setDefaultParams($searchFields, $fieldParams); + $this->view->queries = $this->search->getQueryPairs($module); + $this->view->queryID = $queryID; + $this->display(); + } + + /** + * Build query + * + * @access public + * @return void + */ + public function buildQuery() + { + $this->search->buildQuery(); + die(js::locate($this->post->actionURL, 'parent')); + } + + /** + * Save search query. + * + * @access public + * @return void + */ + public function saveQuery() + { + $this->search->saveQuery(); + if(dao::isError()) die(js::error(dao::getError())); + die('success'); + } + + /** + * Delete a query + * + * @param int $queryID + * @access public + * @return void + */ + public function deleteQuery($queryID) + { + $this->dao->delete()->from(TABLE_USERQUERY)->where('id')->eq($queryID)->andWhere('account')->eq($this->app->user->account)->exec(); + die(js::reload('parent')); + } + + /** + * Create a select page of stories or tasks. + * + * @param int $productID + * @param int $projectID + * @param string $module + * @param int $moduleID + * @access public + * @return void + */ + public function select($productID, $projectID, $module, $moduleID) + { + $this->loadModel('product'); + $this->loadModel('task'); + + if($module == 'story') + { + $fieldParams = $this->config->product->search; + $moduleTitles = $projectID ? $this->loadModel('story')->getProjectStoryPairs($projectID, $productID) : $this->loadModel('story')->getProductStoryPairs($productID); + } + else if($module == 'task') + { + $fieldParams = $this->config->task->search; + $moduleTitles = $this->loadModel('task')->getProjectTaskPairs($projectID); + } + $searchFields = $fieldParams['fields']; + $fieldParams = $fieldParams['params']; + $this->search->initSession($module, $searchFields, $fieldParams); + + if(!empty($_POST['value1'])) $moduleTitles = $this->search->getBySelect($module, array_keys($moduleTitles), $_POST); + + $this->view->module = $module; + $this->view->moduleID = $moduleID; + $this->view->moduleTitles = $moduleTitles; + $this->view->searchFields = $searchFields; + $this->view->fieldParams = $this->search->setDefaultParams($searchFields, $fieldParams); + + die($this->display()); + } +} diff --git a/module/search/lang/en.php b/module/search/lang/en.php index 8f8cfb4a33..10869a2d91 100644 --- a/module/search/lang/en.php +++ b/module/search/lang/en.php @@ -1,46 +1,46 @@ - - * @package search - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->search->common = 'Search'; -$lang->search->reset = 'Reset'; -$lang->search->more = 'More'; -$lang->search->lite = 'Lite'; -$lang->search->saveQuery = 'Save'; -$lang->search->myQuery = 'My queries'; -$lang->search->group1 = '1'; -$lang->search->group2 = '2'; -$lang->search->buildForm = 'Search form'; -$lang->search->buildQuery = 'Execute query'; -$lang->search->saveQuery = 'Save query'; -$lang->search->deleteQuery = 'Delete query'; -$lang->search->setQueryTitle = 'Please input the title(execute searching before save):'; -$lang->search->storyTitle = 'Story title'; -$lang->search->taskTitle = 'Task title'; -$lang->search->select = 'Stories/Tasks filter'; - -$lang->search->operators['='] = '='; -$lang->search->operators['!='] = '!='; -$lang->search->operators['>'] = '>'; -$lang->search->operators['>='] = '>='; -$lang->search->operators['<'] = '<'; -$lang->search->operators['<='] = '<='; -$lang->search->operators['include'] = 'include'; -$lang->search->operators['notinclude'] = 'not include'; - -$lang->search->andor['and'] = 'And'; -$lang->search->andor['or'] = 'Or'; - -$lang->search->null = 'Null'; - -$lang->userquery->title = 'Title'; -$lang->userquery->myQueries = 'My queries'; -$lang->userquery->execut = 'Execute'; -$lang->userquery->delete = 'Delete'; + + * @package search + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->search->common = 'Search'; +$lang->search->reset = 'Reset'; +$lang->search->more = 'More'; +$lang->search->lite = 'Lite'; +$lang->search->saveQuery = 'Save'; +$lang->search->myQuery = 'My queries'; +$lang->search->group1 = '1'; +$lang->search->group2 = '2'; +$lang->search->buildForm = 'Search form'; +$lang->search->buildQuery = 'Execute query'; +$lang->search->saveQuery = 'Save query'; +$lang->search->deleteQuery = 'Delete query'; +$lang->search->setQueryTitle = 'Please input the title(execute searching before save):'; +$lang->search->storyTitle = 'Story title'; +$lang->search->taskTitle = 'Task title'; +$lang->search->select = 'Stories/Tasks filter'; + +$lang->search->operators['='] = '='; +$lang->search->operators['!='] = '!='; +$lang->search->operators['>'] = '>'; +$lang->search->operators['>='] = '>='; +$lang->search->operators['<'] = '<'; +$lang->search->operators['<='] = '<='; +$lang->search->operators['include'] = 'include'; +$lang->search->operators['notinclude'] = 'not include'; + +$lang->search->andor['and'] = 'And'; +$lang->search->andor['or'] = 'Or'; + +$lang->search->null = 'Null'; + +$lang->userquery->title = 'Title'; +$lang->userquery->myQueries = 'My queries'; +$lang->userquery->execut = 'Execute'; +$lang->userquery->delete = 'Delete'; diff --git a/module/search/lang/zh-cn.php b/module/search/lang/zh-cn.php index 3800bf3f42..83f10d3d0b 100644 --- a/module/search/lang/zh-cn.php +++ b/module/search/lang/zh-cn.php @@ -1,46 +1,46 @@ - - * @package search - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->search->common = '搜索'; -$lang->search->reset = '重置'; -$lang->search->more = '更多'; -$lang->search->lite = '简洁'; -$lang->search->saveQuery = '保存'; -$lang->search->myQuery = '我的查询'; -$lang->search->group1 = '第一组'; -$lang->search->group2 = '第二组'; -$lang->search->buildForm = '搜索表单'; -$lang->search->buildQuery = '执行搜索'; -$lang->search->saveQuery = '保存查询'; -$lang->search->deleteQuery = '删除查询'; -$lang->search->setQueryTitle = '请输入查询标题(保存之前请先查询):'; -$lang->search->storyTitle = '需求名称'; -$lang->search->taskTitle = '任务名称'; -$lang->search->select = '需求/任务筛选'; - -$lang->search->operators['='] = '='; -$lang->search->operators['!='] = '!='; -$lang->search->operators['>'] = '>'; -$lang->search->operators['>='] = '>='; -$lang->search->operators['<'] = '<'; -$lang->search->operators['<='] = '<='; -$lang->search->operators['include'] = '包含'; -$lang->search->operators['notinclude'] = '不包含'; - -$lang->search->andor['and'] = '并且'; -$lang->search->andor['or'] = '或者'; - -$lang->search->null = '空'; - -$lang->userquery->title = '查询标题'; -$lang->userquery->myQueries = '我的查询'; -$lang->userquery->execut = '执行'; -$lang->userquery->delete = '删除'; + + * @package search + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->search->common = '搜索'; +$lang->search->reset = '重置'; +$lang->search->more = '更多'; +$lang->search->lite = '简洁'; +$lang->search->saveQuery = '保存'; +$lang->search->myQuery = '我的查询'; +$lang->search->group1 = '第一组'; +$lang->search->group2 = '第二组'; +$lang->search->buildForm = '搜索表单'; +$lang->search->buildQuery = '执行搜索'; +$lang->search->saveQuery = '保存查询'; +$lang->search->deleteQuery = '删除查询'; +$lang->search->setQueryTitle = '请输入查询标题(保存之前请先查询):'; +$lang->search->storyTitle = '需求名称'; +$lang->search->taskTitle = '任务名称'; +$lang->search->select = '需求/任务筛选'; + +$lang->search->operators['='] = '='; +$lang->search->operators['!='] = '!='; +$lang->search->operators['>'] = '>'; +$lang->search->operators['>='] = '>='; +$lang->search->operators['<'] = '<'; +$lang->search->operators['<='] = '<='; +$lang->search->operators['include'] = '包含'; +$lang->search->operators['notinclude'] = '不包含'; + +$lang->search->andor['and'] = '并且'; +$lang->search->andor['or'] = '或者'; + +$lang->search->null = '空'; + +$lang->userquery->title = '查询标题'; +$lang->userquery->myQueries = '我的查询'; +$lang->userquery->execut = '执行'; +$lang->userquery->delete = '删除'; diff --git a/module/search/lang/zh-tw.php b/module/search/lang/zh-tw.php index 0c38298a77..46a071d792 100644 --- a/module/search/lang/zh-tw.php +++ b/module/search/lang/zh-tw.php @@ -1,46 +1,46 @@ - - * @package search - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->search->common = '搜索'; -$lang->search->reset = '重置'; -$lang->search->more = '更多'; -$lang->search->lite = '簡潔'; -$lang->search->saveQuery = '保存'; -$lang->search->myQuery = '我的查詢'; -$lang->search->group1 = '第一組'; -$lang->search->group2 = '第二組'; -$lang->search->buildForm = '搜索表單'; -$lang->search->buildQuery = '執行搜索'; -$lang->search->saveQuery = '保存查詢'; -$lang->search->deleteQuery = '刪除查詢'; -$lang->search->setQueryTitle = '請輸入查詢標題(保存之前請先查詢):'; -$lang->search->storyTitle = '需求名稱'; -$lang->search->taskTitle = '任務名稱'; -$lang->search->select = '需求/任務篩選'; - -$lang->search->operators['='] = '='; -$lang->search->operators['!='] = '!='; -$lang->search->operators['>'] = '>'; -$lang->search->operators['>='] = '>='; -$lang->search->operators['<'] = '<'; -$lang->search->operators['<='] = '<='; -$lang->search->operators['include'] = '包含'; -$lang->search->operators['notinclude'] = '不包含'; - -$lang->search->andor['and'] = '並且'; -$lang->search->andor['or'] = '或者'; - -$lang->search->null = '空'; - -$lang->userquery->title = '查詢標題'; -$lang->userquery->myQueries = '我的查詢'; -$lang->userquery->execut = '執行'; -$lang->userquery->delete = '刪除'; + + * @package search + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->search->common = '搜索'; +$lang->search->reset = '重置'; +$lang->search->more = '更多'; +$lang->search->lite = '簡潔'; +$lang->search->saveQuery = '保存'; +$lang->search->myQuery = '我的查詢'; +$lang->search->group1 = '第一組'; +$lang->search->group2 = '第二組'; +$lang->search->buildForm = '搜索表單'; +$lang->search->buildQuery = '執行搜索'; +$lang->search->saveQuery = '保存查詢'; +$lang->search->deleteQuery = '刪除查詢'; +$lang->search->setQueryTitle = '請輸入查詢標題(保存之前請先查詢):'; +$lang->search->storyTitle = '需求名稱'; +$lang->search->taskTitle = '任務名稱'; +$lang->search->select = '需求/任務篩選'; + +$lang->search->operators['='] = '='; +$lang->search->operators['!='] = '!='; +$lang->search->operators['>'] = '>'; +$lang->search->operators['>='] = '>='; +$lang->search->operators['<'] = '<'; +$lang->search->operators['<='] = '<='; +$lang->search->operators['include'] = '包含'; +$lang->search->operators['notinclude'] = '不包含'; + +$lang->search->andor['and'] = '並且'; +$lang->search->andor['or'] = '或者'; + +$lang->search->null = '空'; + +$lang->userquery->title = '查詢標題'; +$lang->userquery->myQueries = '我的查詢'; +$lang->userquery->execut = '執行'; +$lang->userquery->delete = '刪除'; diff --git a/module/search/model.php b/module/search/model.php index c45a4eed57..fee0f5585c 100644 --- a/module/search/model.php +++ b/module/search/model.php @@ -1,269 +1,269 @@ - - * @package search - * @version $Id$ - * @link http://www.zentao.net - */ -?> -config->search->groupItems; - $groupAndOr = strtoupper($this->post->groupAndOr); - if($groupAndOr != 'AND' and $groupAndOr != 'OR') $groupAndOr = 'AND'; - - for($i = 1; $i <= $groupItems * 2; $i ++) - { - /* The and or between two groups. */ - if($i == 1) $where .= '( 1 '; - if($i == $groupItems + 1) $where .= " ) $groupAndOr ( 1 "; - - /* Set var names. */ - $fieldName = "field$i"; - $andOrName = "andOr$i"; - $operatorName = "operator$i"; - $valueName = "value$i"; - - /* Skip empty vales. */ - if($this->post->$valueName == false) continue; - if($this->post->$valueName == 'null') $this->post->$valueName = ''; // Null is special, stands to empty. - - /* Set and or. */ - $andOr = strtoupper($this->post->$andOrName); - if($andOr != 'AND' and $andOr != 'OR') $andOr = 'AND'; - $where .= " $andOr "; - - /* Set filed name. */ - $where .= '`' . $this->post->$fieldName . '` '; - - /* Set operator. */ - $value = $this->post->$valueName; - $operator = $this->post->$operatorName; - if(!isset($this->lang->search->operators[$operator])) $operator = '='; - if($operator == "include") - { - $where .= ' LIKE ' . $this->dbh->quote("%$value%"); - } - elseif($operator == "notinclude") - { - $where .= ' NOT LIKE ' . $this->dbh->quote("%$value%"); - } - else - { - $where .= $operator . ' ' . $this->dbh->quote($value) . ' '; - } - } - - $where .=" )"; - - /* Save to session. */ - $querySessionName = $this->post->module . 'Query'; - $formSessionName = $this->post->module . 'Form'; - $this->session->set($querySessionName, $where); - $this->session->set($formSessionName, $_POST); - } - - /** - * Init the search session for the first time search. - * - * @param string $module - * @param array $fields - * @param array $fieldParams - * @access public - * @return void - */ - public function initSession($module, $fields, $fieldParams) - { - $formSessionName = $module . 'Form'; - if($this->session->$formSessionName != false) return; - - for($i = 1; $i <= $this->config->search->groupItems * 2; $i ++) - { - /* Var names. */ - $fieldName = "field$i"; - $andOrName = "andOr$i"; - $operatorName = "operator$i"; - $valueName = "value$i"; - - $currentField = key($fields); - $operator = isset($fieldParams[$currentField]['operator']) ? $fieldParams[$currentField]['operator'] : '='; - - $queryForm[$fieldName] = key($fields); - $queryForm[$andOrName] = 'and'; - $queryForm[$operatorName] = $operator; - $queryForm[$valueName] = ''; - - if(!next($fields)) reset($fields); - } - $queryForm['groupAndOr'] = 'and'; - $this->session->set($formSessionName, $queryForm); - } - - /** - * Set default params for selection. - * - * @param array $fields - * @param array $params - * @access public - * @return array - */ - public function setDefaultParams($fields, $params) - { - $users = $this->loadModel('user')->getPairs(); - $products = array('' => '') + $this->loadModel('product')->getPairs(); - $projects = array('' => '') + $this->loadModel('project')->getPairs(); - $fields = array_keys($fields); - foreach($fields as $fieldName) - { - if(!isset($params[$fieldName])) $params[$fieldName] = array('operator' => '=', 'control' => 'input', 'values' => ''); - if($params[$fieldName]['values'] == 'users') $params[$fieldName]['values'] = $users; - if($params[$fieldName]['values'] == 'products') $params[$fieldName]['values'] = $products; - if($params[$fieldName]['values'] == 'projects') $params[$fieldName]['values'] = $projects; - if(is_array($params[$fieldName]['values'])) $params[$fieldName]['values'] = $params[$fieldName]['values'] + array('null' => $this->lang->search->null); - } - return $params; - } - - /** - * Get a query. - * - * @param int $queryID - * @access public - * @return string - */ - public function getQuery($queryID) - { - $query = $this->dao->findByID($queryID)->from(TABLE_USERQUERY)->fetch(); - if(!$query) return false; - $query->form = unserialize($query->form); - return $query; - } - - /** - * Save current query to db. - * - * @access public - * @return void - */ - public function saveQuery() - { - $sqlVar = $this->post->module . 'Query'; - $formVar = $this->post->module . 'Form'; - $sql = $this->session->$sqlVar; - if(!$sql) $sql = ' 1 = 1 '; - - $query = fixer::input('post') - ->specialChars('title') - ->add('account', $this->app->user->account) - ->add('form', serialize($this->session->$formVar)) - ->add('sql', $sql) - ->get(); - $this->dao->insert(TABLE_USERQUERY)->data($query)->autoCheck()->check('title', 'notempty')->exec(); - } - - /** - * Get title => id pairs of a user. - * - * @param string $module - * @access public - * @return array - */ - public function getQueryPairs($module) - { - $queries = $this->dao->select('id, title') - ->from(TABLE_USERQUERY) - ->where('account')->eq($this->app->user->account) - ->andWhere('module')->eq($module) - ->orderBy('id_asc') - ->fetchPairs(); - if(!$queries) return array('' => $this->lang->search->myQuery); - $queries = array('' => $this->lang->search->myQuery) + $queries; - return $queries; - } - - /** - * Get records by the conditon. - * - * @param string $module - * @param string $moduleIds - * @param string $conditions - * @access public - * @return array - */ - public function getBySelect($module, $moduleIds, $conditions) - { - if($module == 'story') - { - $pairs = 'id,title'; - $table = 'zt_story'; - } - else if($module == 'task') - { - $pairs = 'id,name'; - $table = 'zt_task'; - } - $query = '`' . $conditions['field1'] . '`'; - $operator = $conditions['operator1']; - $value = $conditions['value1']; - - if(!isset($this->lang->search->operators[$operator])) $operator = '='; - if($operator == "include") - { - $query .= ' LIKE ' . $this->dbh->quote("%$value%"); - } - elseif($operator == "notinclude") - { - $where .= ' NOT LIKE ' . $this->dbh->quote("%$value%"); - } - else - { - $query .= $operator . ' ' . $this->dbh->quote($value) . ' '; - } - - foreach($moduleIds as $id) - { - if(!$id) continue; - $title = $this->dao->select($pairs) - ->from($table) - ->where('id')->eq((int)$id) - ->andWhere($query) - ->fetch(); - if($title) $results[$id] = $title; - } - if(!isset($results)) return array(); - return $this->formatResults($results, $module); - } - - /** - * Format the results. - * - * @param array $results - * @param string $module - * @access public - * @return array - */ - public function formatResults($results, $module) - { - /* Get title field. */ - $title = ($module == 'story') ? 'title' : 'name'; - $resultPairs = array('' => ''); - foreach($results as $result) $resultPairs[$result->id] = $result->id . ':' . $result->$title; - return $resultPairs; - } - -} + + * @package search + * @version $Id$ + * @link http://www.zentao.net + */ +?> +config->search->groupItems; + $groupAndOr = strtoupper($this->post->groupAndOr); + if($groupAndOr != 'AND' and $groupAndOr != 'OR') $groupAndOr = 'AND'; + + for($i = 1; $i <= $groupItems * 2; $i ++) + { + /* The and or between two groups. */ + if($i == 1) $where .= '( 1 '; + if($i == $groupItems + 1) $where .= " ) $groupAndOr ( 1 "; + + /* Set var names. */ + $fieldName = "field$i"; + $andOrName = "andOr$i"; + $operatorName = "operator$i"; + $valueName = "value$i"; + + /* Skip empty vales. */ + if($this->post->$valueName == false) continue; + if($this->post->$valueName == 'null') $this->post->$valueName = ''; // Null is special, stands to empty. + + /* Set and or. */ + $andOr = strtoupper($this->post->$andOrName); + if($andOr != 'AND' and $andOr != 'OR') $andOr = 'AND'; + $where .= " $andOr "; + + /* Set filed name. */ + $where .= '`' . $this->post->$fieldName . '` '; + + /* Set operator. */ + $value = $this->post->$valueName; + $operator = $this->post->$operatorName; + if(!isset($this->lang->search->operators[$operator])) $operator = '='; + if($operator == "include") + { + $where .= ' LIKE ' . $this->dbh->quote("%$value%"); + } + elseif($operator == "notinclude") + { + $where .= ' NOT LIKE ' . $this->dbh->quote("%$value%"); + } + else + { + $where .= $operator . ' ' . $this->dbh->quote($value) . ' '; + } + } + + $where .=" )"; + + /* Save to session. */ + $querySessionName = $this->post->module . 'Query'; + $formSessionName = $this->post->module . 'Form'; + $this->session->set($querySessionName, $where); + $this->session->set($formSessionName, $_POST); + } + + /** + * Init the search session for the first time search. + * + * @param string $module + * @param array $fields + * @param array $fieldParams + * @access public + * @return void + */ + public function initSession($module, $fields, $fieldParams) + { + $formSessionName = $module . 'Form'; + if($this->session->$formSessionName != false) return; + + for($i = 1; $i <= $this->config->search->groupItems * 2; $i ++) + { + /* Var names. */ + $fieldName = "field$i"; + $andOrName = "andOr$i"; + $operatorName = "operator$i"; + $valueName = "value$i"; + + $currentField = key($fields); + $operator = isset($fieldParams[$currentField]['operator']) ? $fieldParams[$currentField]['operator'] : '='; + + $queryForm[$fieldName] = key($fields); + $queryForm[$andOrName] = 'and'; + $queryForm[$operatorName] = $operator; + $queryForm[$valueName] = ''; + + if(!next($fields)) reset($fields); + } + $queryForm['groupAndOr'] = 'and'; + $this->session->set($formSessionName, $queryForm); + } + + /** + * Set default params for selection. + * + * @param array $fields + * @param array $params + * @access public + * @return array + */ + public function setDefaultParams($fields, $params) + { + $users = $this->loadModel('user')->getPairs(); + $products = array('' => '') + $this->loadModel('product')->getPairs(); + $projects = array('' => '') + $this->loadModel('project')->getPairs(); + $fields = array_keys($fields); + foreach($fields as $fieldName) + { + if(!isset($params[$fieldName])) $params[$fieldName] = array('operator' => '=', 'control' => 'input', 'values' => ''); + if($params[$fieldName]['values'] == 'users') $params[$fieldName]['values'] = $users; + if($params[$fieldName]['values'] == 'products') $params[$fieldName]['values'] = $products; + if($params[$fieldName]['values'] == 'projects') $params[$fieldName]['values'] = $projects; + if(is_array($params[$fieldName]['values'])) $params[$fieldName]['values'] = $params[$fieldName]['values'] + array('null' => $this->lang->search->null); + } + return $params; + } + + /** + * Get a query. + * + * @param int $queryID + * @access public + * @return string + */ + public function getQuery($queryID) + { + $query = $this->dao->findByID($queryID)->from(TABLE_USERQUERY)->fetch(); + if(!$query) return false; + $query->form = unserialize($query->form); + return $query; + } + + /** + * Save current query to db. + * + * @access public + * @return void + */ + public function saveQuery() + { + $sqlVar = $this->post->module . 'Query'; + $formVar = $this->post->module . 'Form'; + $sql = $this->session->$sqlVar; + if(!$sql) $sql = ' 1 = 1 '; + + $query = fixer::input('post') + ->specialChars('title') + ->add('account', $this->app->user->account) + ->add('form', serialize($this->session->$formVar)) + ->add('sql', $sql) + ->get(); + $this->dao->insert(TABLE_USERQUERY)->data($query)->autoCheck()->check('title', 'notempty')->exec(); + } + + /** + * Get title => id pairs of a user. + * + * @param string $module + * @access public + * @return array + */ + public function getQueryPairs($module) + { + $queries = $this->dao->select('id, title') + ->from(TABLE_USERQUERY) + ->where('account')->eq($this->app->user->account) + ->andWhere('module')->eq($module) + ->orderBy('id_asc') + ->fetchPairs(); + if(!$queries) return array('' => $this->lang->search->myQuery); + $queries = array('' => $this->lang->search->myQuery) + $queries; + return $queries; + } + + /** + * Get records by the conditon. + * + * @param string $module + * @param string $moduleIds + * @param string $conditions + * @access public + * @return array + */ + public function getBySelect($module, $moduleIds, $conditions) + { + if($module == 'story') + { + $pairs = 'id,title'; + $table = 'zt_story'; + } + else if($module == 'task') + { + $pairs = 'id,name'; + $table = 'zt_task'; + } + $query = '`' . $conditions['field1'] . '`'; + $operator = $conditions['operator1']; + $value = $conditions['value1']; + + if(!isset($this->lang->search->operators[$operator])) $operator = '='; + if($operator == "include") + { + $query .= ' LIKE ' . $this->dbh->quote("%$value%"); + } + elseif($operator == "notinclude") + { + $where .= ' NOT LIKE ' . $this->dbh->quote("%$value%"); + } + else + { + $query .= $operator . ' ' . $this->dbh->quote($value) . ' '; + } + + foreach($moduleIds as $id) + { + if(!$id) continue; + $title = $this->dao->select($pairs) + ->from($table) + ->where('id')->eq((int)$id) + ->andWhere($query) + ->fetch(); + if($title) $results[$id] = $title; + } + if(!isset($results)) return array(); + return $this->formatResults($results, $module); + } + + /** + * Format the results. + * + * @param array $results + * @param string $module + * @access public + * @return array + */ + public function formatResults($results, $module) + { + /* Get title field. */ + $title = ($module == 'story') ? 'title' : 'name'; + $resultPairs = array('' => ''); + foreach($results as $result) $resultPairs[$result->id] = $result->id . ':' . $result->$title; + return $resultPairs; + } + +} diff --git a/module/search/view/buildform.html.php b/module/search/view/buildform.html.php index afa548dd75..99e9f510f0 100644 --- a/module/search/view/buildform.html.php +++ b/module/search/view/buildform.html.php @@ -1,262 +1,262 @@ - - * @package search - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          ' target='hiddenwin' id='searchform'> - - - - - - - - - - -
          search->common;?> - - session->$formSessionName; - - $fieldNO = 1; - for($i = 1; $i <= $groupItems; $i ++) - { - $spanClass = $i == 1 ? 'inline' : 'hidden'; - echo ""; - - /* Get params of current field. */ - $currentField = $formSession["field$fieldNO"]; - $param = $fieldParams[$currentField]; - - /* Print and or. */ - if($i == 1) echo "{$lang->search->group1}" . html::hidden("andOr$fieldNO", 'AND'); - if($i > 1) echo "
          " . html::select("andOr$fieldNO", $lang->search->andor, $formSession["andOr$fieldNO"]); - - /* Print field. */ - echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); - - /* Print operator. */ - echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); - - /* Print value. */ - echo ""; - if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-2'); - if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-2'); - echo ''; - - $fieldNO ++; - echo '
          '; - } - ?> -
          -
          search->andor, $formSession['groupAndOr'])?> - - "; - - /* Get params of current field. */ - $currentField = $formSession["field$fieldNO"]; - $param = $fieldParams[$currentField]; - - /* Print and or. */ - if($i == 1) echo "{$lang->search->group2}" . html::hidden("andOr$fieldNO", 'AND'); - if($i > 1) echo "
          " . html::select("andOr$fieldNO", $lang->search->andor, $formSession["andOr$fieldNO"]); - - /* Print field. */ - echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); - - /* Print operator. */ - echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); - - /* Print value. */ - echo ""; - if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-2'); - if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-2'); - echo ''; - - $fieldNO ++; - echo ''; - } - ?> -
          -
          - - search->common); - echo html::commonButton($lang->search->reset, 'onclick=resetForm();'); - echo html::commonButton($lang->save, 'onclick=saveQuery()'); - ?> - - - - - search->more;?> - - -
          -
          - + + * @package search + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          ' target='hiddenwin' id='searchform'> + + + + + + + + + + +
          search->common;?> + + session->$formSessionName; + + $fieldNO = 1; + for($i = 1; $i <= $groupItems; $i ++) + { + $spanClass = $i == 1 ? 'inline' : 'hidden'; + echo ""; + + /* Get params of current field. */ + $currentField = $formSession["field$fieldNO"]; + $param = $fieldParams[$currentField]; + + /* Print and or. */ + if($i == 1) echo "{$lang->search->group1}" . html::hidden("andOr$fieldNO", 'AND'); + if($i > 1) echo "
          " . html::select("andOr$fieldNO", $lang->search->andor, $formSession["andOr$fieldNO"]); + + /* Print field. */ + echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); + + /* Print operator. */ + echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); + + /* Print value. */ + echo ""; + if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-2'); + if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-2'); + echo ''; + + $fieldNO ++; + echo '
          '; + } + ?> +
          +
          search->andor, $formSession['groupAndOr'])?> + + "; + + /* Get params of current field. */ + $currentField = $formSession["field$fieldNO"]; + $param = $fieldParams[$currentField]; + + /* Print and or. */ + if($i == 1) echo "{$lang->search->group2}" . html::hidden("andOr$fieldNO", 'AND'); + if($i > 1) echo "
          " . html::select("andOr$fieldNO", $lang->search->andor, $formSession["andOr$fieldNO"]); + + /* Print field. */ + echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); + + /* Print operator. */ + echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); + + /* Print value. */ + echo ""; + if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-2'); + if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-2'); + echo ''; + + $fieldNO ++; + echo ''; + } + ?> +
          +
          + + search->common); + echo html::commonButton($lang->search->reset, 'onclick=resetForm();'); + echo html::commonButton($lang->save, 'onclick=saveQuery()'); + ?> + + + + + search->more;?> + + +
          +
          + diff --git a/module/search/view/select.html.php b/module/search/view/select.html.php index 5c8503c937..0d8643da1c 100644 --- a/module/search/view/select.html.php +++ b/module/search/view/select.html.php @@ -1,91 +1,91 @@ - - * @package search - * @version $Id: select.html.php 942 2010-07-06 10:03:51Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          - - - session->$formSessionName; - $fieldNO = 1; - - /* 取当前字段的设置。*/ - $currentField = $formSession["field$fieldNO"]; - $param = $fieldParams[$currentField]; - /* 打印字段。*/ - echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); - - /* 打印操作符。*/ - echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); - - /* 打印值。*/ - echo ""; - if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-4'); - if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-4'); - echo ''; - ?> - - search->common);?> - - - - - - - - $title):?> - - - - - - - -
          search->{$module . 'Title'};?>search->select;?>
          >
          -
          + + * @package search + * @version $Id: select.html.php 942 2010-07-06 10:03:51Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          + + + session->$formSessionName; + $fieldNO = 1; + + /* 取当前字段的设置。*/ + $currentField = $formSession["field$fieldNO"]; + $param = $fieldParams[$currentField]; + /* 打印字段。*/ + echo html::select("field$fieldNO", $searchFields, $formSession["field$fieldNO"], "onchange='setField(this.value, $fieldNO)'"); + + /* 打印操作符。*/ + echo html::select("operator$fieldNO", $lang->search->operators, $formSession["operator$fieldNO"]); + + /* 打印值。*/ + echo ""; + if($param['control'] == 'select') echo html::select("value$fieldNO", $param['values'], $formSession["value$fieldNO"], 'class=select-4'); + if($param['control'] == 'input') echo html::input("value$fieldNO", $formSession["value$fieldNO"], 'class=text-4'); + echo ''; + ?> + + search->common);?> + + + + + + + + $title):?> + + + + + + + +
          search->{$module . 'Title'};?>search->select;?>
          >
          +
          diff --git a/module/setting/model.php b/module/setting/model.php index 886a7a1a15..e41415b3a3 100644 --- a/module/setting/model.php +++ b/module/setting/model.php @@ -1,124 +1,124 @@ - - * @package setting - * @version $Id$ - * @link http://www.zentao.net - */ -?> -getItem('system', 'global', 'version'); - if($version) return $version; - return '0.3 beta'; - } - - /** - * Get value of an item. - * - * @param string $owner - * @param string $section - * @param string $key - * @access public - * @return misc - */ - public function getItem($owner, $section, $key) - { - return $this->dao->select('`value`')->from(TABLE_CONFIG) - ->where('company')->eq(0) - ->andWhere('owner')->eq($owner) - ->andWhere('section')->eq($section) - ->andWhere('`key`')->eq($key) - ->fetch('value', $autoCompany = false); - } - - /** - * Compute a SN. Use the server ip, and server software string as seed, and an rand number, two micro time - * - * Note: this sn just to unique this zentaopms. No any private info. - * - * @access public - * @return string - */ - public function computeSN() - { - $seed = $this->server->SERVER_ADDR . $this->server->SERVER_SOFTWARE; - $sn = md5(str_shuffle(md5($seed . mt_rand(0, 99999999) . microtime())) . microtime()); - return $sn; - } - - /** - * Set the sn of current zentaopms. - * - * @access public - * @return void - */ - public function setSN() - { - $item->company = 0; - $item->owner = 'system'; - $item->section = 'global'; - $item->key = 'sn'; - $item->value = $this->computeSN(); - - $config = $this->dao->select('id, value')->from(TABLE_CONFIG) - ->where('company')->eq(0) - ->andWhere('owner')->eq('system') - ->andWhere('section')->eq('global') - ->andWhere('`key`')->eq('sn') - ->fetch('', $autoComapny = false); - if(!$config) - { - $this->dao->insert(TABLE_CONFIG)->data($item)->exec($autoCompany = false); - } - elseif($config->value == '281602d8ff5ee7533eeafd26eda4e776' or $config->value == '9bed3108092c94a0db2b934a46268b4a') - { - $this->dao->update(TABLE_CONFIG)->data($item)->where('id')->eq($config->id)->exec($autoCompany = false); - } - } - - /** - * Update version - * - * @param string $version - * @access public - * @return void - */ - public function updateVersion($version) - { - $item->company = 0; - $item->owner = 'system'; - $item->section = 'global'; - $item->key = 'version'; - $item->value = $version; - - $configID = $this->dao->select('id')->from(TABLE_CONFIG) - ->where('company')->eq(0) - ->andWhere('owner')->eq('system') - ->andWhere('section')->eq('global') - ->andWhere('`key`')->eq('version') - ->fetch('id', $autoComapny = false); - if($configID > 0) - { - $this->dao->update(TABLE_CONFIG)->data($item)->where('id')->eq($configID)->exec($autoCompany = false); - } - else - { - $this->dao->insert(TABLE_CONFIG)->data($item)->exec($autoCompany = false); - } - } -} + + * @package setting + * @version $Id$ + * @link http://www.zentao.net + */ +?> +getItem('system', 'global', 'version'); + if($version) return $version; + return '0.3 beta'; + } + + /** + * Get value of an item. + * + * @param string $owner + * @param string $section + * @param string $key + * @access public + * @return misc + */ + public function getItem($owner, $section, $key) + { + return $this->dao->select('`value`')->from(TABLE_CONFIG) + ->where('company')->eq(0) + ->andWhere('owner')->eq($owner) + ->andWhere('section')->eq($section) + ->andWhere('`key`')->eq($key) + ->fetch('value', $autoCompany = false); + } + + /** + * Compute a SN. Use the server ip, and server software string as seed, and an rand number, two micro time + * + * Note: this sn just to unique this zentaopms. No any private info. + * + * @access public + * @return string + */ + public function computeSN() + { + $seed = $this->server->SERVER_ADDR . $this->server->SERVER_SOFTWARE; + $sn = md5(str_shuffle(md5($seed . mt_rand(0, 99999999) . microtime())) . microtime()); + return $sn; + } + + /** + * Set the sn of current zentaopms. + * + * @access public + * @return void + */ + public function setSN() + { + $item->company = 0; + $item->owner = 'system'; + $item->section = 'global'; + $item->key = 'sn'; + $item->value = $this->computeSN(); + + $config = $this->dao->select('id, value')->from(TABLE_CONFIG) + ->where('company')->eq(0) + ->andWhere('owner')->eq('system') + ->andWhere('section')->eq('global') + ->andWhere('`key`')->eq('sn') + ->fetch('', $autoComapny = false); + if(!$config) + { + $this->dao->insert(TABLE_CONFIG)->data($item)->exec($autoCompany = false); + } + elseif($config->value == '281602d8ff5ee7533eeafd26eda4e776' or $config->value == '9bed3108092c94a0db2b934a46268b4a') + { + $this->dao->update(TABLE_CONFIG)->data($item)->where('id')->eq($config->id)->exec($autoCompany = false); + } + } + + /** + * Update version + * + * @param string $version + * @access public + * @return void + */ + public function updateVersion($version) + { + $item->company = 0; + $item->owner = 'system'; + $item->section = 'global'; + $item->key = 'version'; + $item->value = $version; + + $configID = $this->dao->select('id')->from(TABLE_CONFIG) + ->where('company')->eq(0) + ->andWhere('owner')->eq('system') + ->andWhere('section')->eq('global') + ->andWhere('`key`')->eq('version') + ->fetch('id', $autoComapny = false); + if($configID > 0) + { + $this->dao->update(TABLE_CONFIG)->data($item)->where('id')->eq($configID)->exec($autoCompany = false); + } + else + { + $this->dao->insert(TABLE_CONFIG)->data($item)->exec($autoCompany = false); + } + } +} diff --git a/module/story/control.php b/module/story/control.php index 08cac52f9a..1ea55fed84 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -1,815 +1,815 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -class story extends control -{ - /** - * The construct function, load product, tree, user auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('product'); - $this->loadModel('tree'); - $this->loadModel('user'); - } - - /** - * Create a story. - * - * @param int $productID - * @param int $moduleID - * @access public - * @return void - */ - public function create($productID = 0, $moduleID = 0, $storyID = 0, $projectID = 0, $bugID = 0) - { - if(!empty($_POST)) - { - $storyID = $this->story->create($projectID, $bugID); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action'); - if($bugID == 0) - { - $actionID = $this->action->create('story', $storyID, 'Opened', ''); - } - else - { - $actionID = $this->action->create('story', $storyID, 'Frombug', '', $bugID); - } - $this->sendMail($storyID, $actionID); - if($projectID == 0) - { - die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); - } - else - { - die(js::locate($this->createLink('project', 'story', "projectID=$projectID"), 'parent')); - } - } - - /* Set products, users and module. */ - if($productID != 0) - { - $product = $this->product->getById($productID); - $products = $this->product->getPairs(); - } - else - { - $products = $this->product->getProductsByProject($projectID); - foreach($products as $key => $title) - { - $product = $this->product->getById($key); - break; - } - } - $users = $this->user->getPairs('nodeleted'); - $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story'); - - /* Set menu. */ - $this->product->setMenu($products, $product->id); - - /* Init vars. */ - $planID = 0; - $source = ''; - $pri = 0; - $estimate = ''; - $title = ''; - $spec = ''; - $verify = ''; - $keywords = ''; - $mailto = ''; - - if($storyID > 0) - { - $story = $this->story->getByID($storyID); - $planID = $story->plan; - $source = $story->source; - $pri = $story->pri; - $productID = $story->product; - $moduleID = $story->module; - $estimate = $story->estimate; - $title = $story->title; - $spec = htmlspecialchars($story->spec); - $verify = htmlspecialchars($story->verify); - $keywords = $story->keywords; - $mailto = $story->mailto; - } - - if($bugID > 0) - { - $oldBug = $this->loadModel('bug')->getById($bugID); - $productID = $oldBug->product; - $source = 'bug'; - $title = $oldBug->title; - $keywords = $oldBug->keywords; - $spec = $oldBug->steps; - $pri = $oldBug->pri; - $mailto = $oldBug->mailto; - } - - $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->create; - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name); - $this->view->position[] = $this->lang->story->create; - $this->view->products = $products; - $this->view->users = $users; - $this->view->moduleID = $moduleID; - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->view->plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired'); - $this->view->planID = $planID; - $this->view->source = $source; - $this->view->pri = $pri; - $this->view->productID = $productID; - $this->view->estimate = $estimate; - $this->view->title = $title; - $this->view->spec = $spec; - $this->view->verify = $verify; - $this->view->keywords = $keywords; - $this->view->mailto = $mailto; - - $this->display(); - } - - /** - * Create a batch stories. - * - * @param int $productID - * @param int $moduleID - * @access public - * @return void - */ - public function batchCreate($productID = 0, $moduleID = 0) - { - if(!empty($_POST)) - { - $mails = $this->story->batchCreate($productID); - if(dao::isError()) die(js::error(dao::getError())); - - foreach($mails as $mail) - { - $this->sendMail($mail->storyID, $mail->actionID); - } - die(js::locate($this->createLink('product', 'browse', "productID=$productID"), 'parent')); - } - - /* Set products, users and module. */ - $product = $this->product->getById($productID); - $products = $this->product->getPairs(); - $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story'); - - /* Set menu. */ - $this->product->setMenu($products, $product->id); - - /* Init vars. */ - $planID = 0; - $pri = 0; - $estimate = ''; - $title = ''; - $spec = ''; - - $moduleOptionMenu['same'] = $this->lang->story->same; - $plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired'); - $plans['same'] = $this->lang->story->same; - - $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->create; - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name); - $this->view->position[] = $this->lang->story->create; - $this->view->products = $products; - $this->view->moduleID = $moduleID; - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->view->plans = $plans; - $this->view->planID = $planID; - $this->view->pri = $pri; - $this->view->productID = $productID; - $this->view->estimate = $estimate; - $this->view->title = $title; - $this->view->spec = $spec; - - $this->display(); - } - - /** - * The common action when edit or change a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function commonAction($storyID) - { - /* Get datas. */ - $story = $this->story->getById($storyID); - $product = $this->product->getById($story->product); - $products = $this->product->getPairs(); - $users = $this->user->getPairs('nodeleted'); - $moduleOptionMenu = $this->tree->getOptionMenu($product->id, $viewType = 'story'); - - /* Set menu. */ - $this->product->setMenu($products, $product->id); - - /* Assign. */ - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); - $this->view->product = $product; - $this->view->products = $products; - $this->view->story = $story; - $this->view->users = $users; - $this->view->moduleOptionMenu = $moduleOptionMenu; - $this->view->plans = $this->loadModel('productplan')->getPairs($product->id); - $this->view->actions = $this->action->getList('story', $storyID); - } - - /** - * Edit a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function edit($storyID) - { - $this->loadModel('action'); - if(!empty($_POST)) - { - $changes = $this->story->update($storyID); - if(dao::isError()) die(js::error(dao::getError())); - if($this->post->comment != '' or !empty($changes)) - { - $action = !empty($changes) ? 'Edited' : 'Commented'; - $actionID = $this->action->create('story', $storyID, $action, $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendMail($storyID, $actionID); - } - die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); - } - - $this->commonAction($storyID); - - /* Assign. */ - $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->edit . $this->lang->colon . $this->view->story->title; - $this->view->position[] = $this->lang->story->edit; - $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), $this->view->story->assignedTo); - $this->display(); - } - - /** - * Change a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function change($storyID) - { - $this->loadModel('action'); - if(!empty($_POST)) - { - $changes = $this->story->change($storyID); - if(dao::isError()) die(js::error(dao::getError())); - $version = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch('version'); - $files = $this->loadModel('file')->saveUpload('story', $storyID, $version); - if($this->post->comment != '' or !empty($changes) or !empty($files)) - { - $action = (!empty($changes) or !empty($files)) ? 'Changed' : 'Commented'; - $fileAction = ''; - if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; - $actionID = $this->action->create('story', $storyID, $action, $fileAction . $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendMail($storyID, $actionID); - } - die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); - } - - $this->commonAction($storyID); - $this->story->getAffectedScope($this->view->story); - $this->app->loadLang('task'); - $this->app->loadLang('bug'); - $this->app->loadLang('testcase'); - $this->app->loadLang('project'); - - /* Assign. */ - $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->change . $this->lang->colon . $this->view->story->title; - $this->view->position[] = $this->lang->story->change; - $this->display(); - } - - /** - * Activate a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function activate($storyID) - { - $this->loadModel('action'); - if(!empty($_POST)) - { - $this->story->activate($storyID); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('story', $storyID, 'Activated', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendMail($storyID, $actionID); - die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); - } - - $this->commonAction($storyID); - - /* Assign. */ - $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->activate . $this->lang->colon . $this->view->story->title; - $this->view->position[] = $this->lang->story->activate; - $this->display(); - } - - /** - * View a story. - * - * @param int $storyID - * @param int $version - * @access public - * @return void - */ - public function view($storyID, $version = 0) - { - $this->loadModel('action'); - $storyID = (int)$storyID; - $story = $this->story->getById($storyID, $version); - if(!$story) die(js::error($this->lang->notFound) . js::locate('back')); - - $story->files = $this->loadModel('file')->getByObject('story', $storyID); - $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); - $plan = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title'); - $bugs = $this->dao->select('id,title')->from(TABLE_BUG)->where('story')->eq($storyID)->fetchAll(); - $fromBug = $this->dao->select('id,title')->from(TABLE_BUG)->where('toStory')->eq($storyID)->fetch(); - $cases = $this->dao->select('id,title')->from(TABLE_CASE)->where('story')->eq($storyID)->fetchAll(); - $modulePath = $this->tree->getParents($story->module); - $users = $this->user->getPairs('noletter'); - - /* Set the menu. */ - $this->product->setMenu($this->product->getPairs(), $product->id); - - $header['title'] = $product->name . $this->lang->colon . $this->lang->story->view . $this->lang->colon . $story->title; - $position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); - $position[] = $this->lang->story->view; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->product = $product; - $this->view->plan = $plan; - $this->view->bugs = $bugs; - $this->view->fromBug = $fromBug; - $this->view->cases = $cases; - $this->view->story = $story; - $this->view->users = $users; - $this->view->actions = $this->action->getList('story', $storyID); - $this->view->modulePath = $modulePath; - $this->view->version = $version == 0 ? $story->version : $version; - $this->display(); - } - - /** - * Delete a story. - * - * @param int $storyID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($storyID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->story->confirmDelete, $this->createLink('story', 'delete', "story=$storyID&confirm=yes"), ''); - exit; - } - else - { - $this->story->delete(TABLE_STORY, $storyID); - die(js::locate($this->session->storyList, 'parent')); - } - } - - /** - * Review a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function review($storyID) - { - $this->loadModel('action'); - - if(!empty($_POST)) - { - $this->story->review($storyID); - if(dao::isError()) die(js::error(dao::getError())); - $result = $this->post->result; - if($this->post->closedReason != '' and strpos('done,postponed,subdivided', $this->post->closedReason) !== false) $result = 'pass'; - $actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result)); - $this->action->logHistory($actionID, array()); - $this->sendMail($storyID, $actionID); - if($this->post->result == 'reject') - { - $this->action->create('story', $storyID, 'Closed', '', ucfirst($this->post->closedReason)); - } - die(js::locate(inlink('view', "storyID=$storyID"), 'parent')); - } - - /* Get story and product. */ - $story = $this->story->getById($storyID); - $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); - - /* Set menu. */ - $this->product->setMenu($this->product->getPairs(), $product->id); - - /* Set the review result options. */ - if($story->status == 'draft' and $story->version == 1) unset($this->lang->story->reviewResultList['revert']); - if($story->status == 'changed') unset($this->lang->story->reviewResultList['reject']); - - $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->view . $this->lang->colon . $story->title; - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); - $this->view->position[] = $this->lang->story->view; - - $this->view->product = $product; - $this->view->story = $story; - $this->view->actions = $this->action->getList('story', $storyID); - $this->view->users = $this->loadModel('user')->getPairs('nodeleted'); - - /* Get the affcected things. */ - $this->story->getAffectedScope($this->view->story); - $this->app->loadLang('task'); - $this->app->loadLang('bug'); - $this->app->loadLang('testcase'); - $this->app->loadLang('project'); - - $this->display(); - } - - /** - * Close a story. - * - * @param int $storyID - * @access public - * @return void - */ - public function close($storyID) - { - $this->loadModel('action'); - - if(!empty($_POST)) - { - $this->story->close($storyID); - if(dao::isError()) die(js::error(dao::getError())); - $actionID = $this->action->create('story', $storyID, 'Closed', $this->post->comment, ucfirst($this->post->closedReason)); - $this->action->logHistory($actionID); - $this->sendMail($storyID, $actionID); - die(js::locate(inlink('view', "storyID=$storyID"), 'parent')); - } - - /* Get story and product. */ - $story = $this->story->getById($storyID); - $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); - - /* Set menu. */ - $this->product->setMenu($this->product->getPairs(), $product->id); - - /* Set the closed reason options. */ - if($story->status == 'draft') unset($this->lang->story->reasonList['cancel']); - - $this->view->header->title = $product->name . $this->lang->colon . $this->lang->close . $this->lang->colon . $story->title; - $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); - $this->view->position[] = $this->lang->close; - - $this->view->product = $product; - $this->view->story = $story; - $this->view->actions = $this->action->getList('story', $storyID); - $this->view->users = $this->loadModel('user')->getPairs(); - $this->display(); - } - - /** - * Tasks of a story. - * - * @param int $storyID - * @param int $projectID - * @access public - * @return void - */ - public function tasks($storyID, $projectID = 0) - { - $this->loadModel('task'); - $this->view->tasks = $this->task->getStoryTaskPairs($storyID, $projectID); - $this->display(); - exit; - } - - /** - * AJAX: get stories of a project in html select. - * - * @param int $projectID - * @param int $productID - * @param int $storyID - * @access public - * @return void - */ - public function ajaxGetProjectStories($projectID, $productID = 0, $storyID = 0) - { - $stories = $this->story->getProjectStoryPairs($projectID, $productID); - die(html::select('story', $stories, $storyID)); - } - - /** - * AJAX: get stories of a product in html select. - * - * @param int $productID - * @param int $moduleID - * @param int $storyID - * @access public - * @return void - */ - public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0) - { - $stories = $this->story->getProductStoryPairs($productID, $moduleID); - die(html::select('story', $stories, $storyID, "class=''")); - } - - /** - * Send email. - * - * @param int $storyID - * @param int $actionID - * @access public - * @return void - */ - public function sendmail($storyID, $actionID) - { - $story = $this->story->getById($storyID); - $productName = $this->product->getById($story->product)->name; - - /* Get actions. */ - $action = $this->loadModel('action')->getById($actionID); - $history = $this->action->getHistory($actionID); - $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); - if(strtolower($action->action) == 'opened') $action->comment = $story->spec; - - /* Set toList and ccList. */ - $toList = $story->assignedTo; - $ccList = str_replace(' ', '', trim($story->mailto, ',')); - - /* If the action is changed or reviewed, mail to the project team. */ - if(strtolower($action->action) == 'changed' or strtolower($action->action) == 'reviewed') - { - $prjMembers = $this->story->getProjectMembers($storyID); - if($prjMembers) - { - $ccList .= ',' . join(',', $prjMembers); - $ccList = ltrim($ccList, ','); - } - } - - if($toList == '') - { - if($ccList == '') return; - if(strpos($ccList, ',') === false) - { - $toList = $ccList; - $ccList = ''; - } - else - { - $commaPos = strpos($ccList, ','); - $toList = substr($ccList, 0, $commaPos); - $ccList = substr($ccList, $commaPos + 1); - } - } - elseif($toList == 'closed') - { - $toList = $story->openedBy; - } - - /* Get the mail content. */ - $this->view->story = $story; - $this->view->action = $action; - $this->view->users = $this->user->getPairs('noletter'); - $mailContent = $this->parse($this->moduleName, 'sendmail'); - - /* Send it. */ - $this->loadModel('mail')->send($toList, $productName . ':' . 'STORY #' . $story->id . $this->lang->colon . $story->title, $mailContent, $ccList); - if($this->mail->isError()) echo js::error($this->mail->getError()); - } - /** - * The report page. - * - * @param int $productID - * @param string $browseType - * @param int $moduleID - * @access public - * @return void - */ - public function report($productID, $browseType, $moduleID) - { - $this->loadModel('report'); - $this->view->charts = array(); - $this->view->renderJS = ''; - - if(!empty($_POST)) - { - foreach($this->post->charts as $chart) - { - $chartFunc = 'getDataOf' . $chart; - $chartData = $this->story->$chartFunc(); - $chartOption = $this->lang->story->report->$chart; - $this->story->mergeChartOption($chart); - - $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); - $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); - $this->view->datas[$chart] = $this->report->computePercent($chartData); - } - $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); - } - $this->products = $this->product->getPairs(); - $this->product->setMenu($this->products, $productID); - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->story->common; - $this->view->productID = $productID; - $this->view->browseType = $browseType; - $this->view->moduleID = $moduleID; - $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; - $this->display(); - } - - /** - * get data to export - * - * @param int $productID - * @param string $orderBy - * @access public - * @return void - */ - public function export($productID, $orderBy) - { - /* format the fields of every story in order to export data. */ - if($_POST) - { - $storyLang = $this->lang->story; - $storyConfig = $this->config->story; - - /* Create field lists. */ - $fields = explode(',', $storyConfig->list->exportFields); - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($storyLang->$fieldName) ? $storyLang->$fieldName : $fieldName; - unset($fields[$key]); - } - - /* Get stories. */ - $stories = $this->dao->select('*')->from(TABLE_STORY)->where($this->session->storyReport)->orderBy($orderBy)->fetchAll('id'); - - /* Get users, products and projects. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $products = $this->loadModel('product')->getPairs(); - - /* Get related objects id lists. */ - $relatedModuleIdList = array(); - $relatedStoryIdList = array(); - $relatedPlanIdList = array(); - - foreach($stories as $story) - { - $relatedModuleIdList[$story->module] = $story->module; - $relatedPlanIdList[$story->plan] = $story->plan; - - /* Process related stories. */ - $relatedStories = $story->childStories . ',' . $story->linkStories . ',' . $story->duplicateStory; - $relatedStories = explode(',', $relatedStories); - foreach($relatedStories as $storyID) - { - if($storyID) $relatedStoryIdList[$storyID] = trim($storyID); - } - } - - /* Get related objects title or names. */ - $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); - $relatedPlans = $this->dao->select('id, title')->from(TABLE_PRODUCTPLAN)->where('id')->in($relatedPlanIdList)->fetchPairs(); - $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('story')->andWhere('objectID')->in(@array_keys($stories))->fetchGroup('objectID'); - $relatedSpecs = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('`story`')->in(@array_keys($stories))->orderBy('version desc')->fetchGroup('story'); - - foreach($stories as $story) - { - $story->spec = ''; - $story->verify = ''; - if(isset($relatedSpecs[$story->id])) - { - $storySpec = $relatedSpecs[$story->id][0]; - $story->title = $storySpec->title; - $story->spec = $storySpec->spec; - $story->verify = $storySpec->verify; - } - - if($this->post->fileType == 'csv') - { - $story->spec = htmlspecialchars_decode($story->spec); - $story->spec = str_replace("
          ", "\n", $story->spec); - $story->spec = str_replace('"', '""', $story->spec); - - $story->verify = htmlspecialchars_decode($story->verify); - $story->verify = str_replace("
          ", "\n", $story->verify); - $story->verify = str_replace('"', '""', $story->verify); - } - - /* fill some field with useful value. */ - if(isset($products[$story->product])) $story->product = $products[$story->product]; - if(isset($relatedModules[$story->module])) $story->module = $relatedModules[$story->module]; - if(isset($relatedPlans[$story->plan])) $story->plan = $relatedPlans[$story->plan]; - if(isset($relatedStories[$story->duplicateStory])) $story->duplicateStory = $relatedStories[$story->duplicateStory]; - - if(isset($storyLang->priList[$story->pri])) $story->pri = $storyLang->priList[$story->pri]; - if(isset($storyLang->statusList[$story->status])) $story->status = $storyLang->statusList[$story->status]; - if(isset($storyLang->stageList[$story->stage])) $story->stage = $storyLang->stageList[$story->stage]; - if(isset($storyLang->reasonList[$story->closedReason])) $story->closedReason = $storyLang->reasonList[$story->closedReason]; - - if(isset($users[$story->openedBy])) $story->openedBy = $users[$story->openedBy]; - if(isset($users[$story->assignedTo])) $story->assignedTo = $users[$story->assignedTo]; - if(isset($users[$story->lastEditedBy])) $story->lastEditedBy = $users[$story->lastEditedBy]; - if(isset($users[$story->closedBy])) $story->closedBy = $users[$story->closedBy]; - - $story->openedDate = substr($story->openedDate, 0, 10); - $story->assignedDate = substr($story->assignedDate, 0, 10); - $story->lastEditedDate = substr($story->lastEditedDate, 0, 10); - $story->closedDate = substr($story->closedDate, 0, 10); - - - if($story->linkStories) - { - $tmpLinkStories = array(); - $linkStoriesIdList = explode(',', $story->linkStories); - foreach($linkStoriesIdList as $linkStoryID) - { - $linkStoryID = trim($linkStoryID); - $tmpLinkStories[] = isset($relatedStories[$linkStoryID]) ? $relatedStories[$linkStoryID] : $linkStoryID; - } - $story->linkStories = join("; \n", $tmpLinkStories); - } - - if($story->childStories) - { - $tmpChildStories = array(); - $childStoriesIdList = explode(',', $story->childStories); - foreach($childStoriesIdList as $childStoryID) - { - $childStoryID = trim($childStoryID); - $tmpChildStories[] = isset($relatedStories[$childStoryID]) ? $relatedStories[$childStoryID] : $childStoryID; - } - $story->childStories = join("; \n", $tmpChildStories); - } - - /* Set related files. */ - if(isset($relatedFiles[$story->id])) - { - foreach($relatedFiles[$story->id] as $file) - { - $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$story->company/" . $file->pathname; - $story->files .= html::a($fileURL, $file->title, '_blank') . '
          '; - } - } - - $story->mailto = trim(trim($story->mailto), ','); - $mailtos = explode(',', $story->mailto); - $story->mailto = ''; - foreach($mailtos as $mailto) - { - $mailto = trim($mailto); - if(isset($users[$mailto])) $story->mailto .= $users[$mailto] . ','; - } - - $story->reviewedBy = trim(trim($story->reviewedBy), ','); - $reviewedBys = explode(',', $story->reviewedBy); - $story->reviewedBy = ''; - foreach($reviewedBys as $reviewedBy) - { - $reviewedBy = trim($reviewedBy); - if(isset($users[$reviewedBy])) $story->reviewedBy .= $users[$reviewedBy] . ','; - } - - } - - $this->post->set('fields', $fields); - $this->post->set('rows', $stories); - $this->fetch('file', 'export2' . $this->post->fileType, $_POST); - } - - $this->display(); - } -} + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +class story extends control +{ + /** + * The construct function, load product, tree, user auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('product'); + $this->loadModel('tree'); + $this->loadModel('user'); + } + + /** + * Create a story. + * + * @param int $productID + * @param int $moduleID + * @access public + * @return void + */ + public function create($productID = 0, $moduleID = 0, $storyID = 0, $projectID = 0, $bugID = 0) + { + if(!empty($_POST)) + { + $storyID = $this->story->create($projectID, $bugID); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action'); + if($bugID == 0) + { + $actionID = $this->action->create('story', $storyID, 'Opened', ''); + } + else + { + $actionID = $this->action->create('story', $storyID, 'Frombug', '', $bugID); + } + $this->sendMail($storyID, $actionID); + if($projectID == 0) + { + die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); + } + else + { + die(js::locate($this->createLink('project', 'story', "projectID=$projectID"), 'parent')); + } + } + + /* Set products, users and module. */ + if($productID != 0) + { + $product = $this->product->getById($productID); + $products = $this->product->getPairs(); + } + else + { + $products = $this->product->getProductsByProject($projectID); + foreach($products as $key => $title) + { + $product = $this->product->getById($key); + break; + } + } + $users = $this->user->getPairs('nodeleted'); + $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story'); + + /* Set menu. */ + $this->product->setMenu($products, $product->id); + + /* Init vars. */ + $planID = 0; + $source = ''; + $pri = 0; + $estimate = ''; + $title = ''; + $spec = ''; + $verify = ''; + $keywords = ''; + $mailto = ''; + + if($storyID > 0) + { + $story = $this->story->getByID($storyID); + $planID = $story->plan; + $source = $story->source; + $pri = $story->pri; + $productID = $story->product; + $moduleID = $story->module; + $estimate = $story->estimate; + $title = $story->title; + $spec = htmlspecialchars($story->spec); + $verify = htmlspecialchars($story->verify); + $keywords = $story->keywords; + $mailto = $story->mailto; + } + + if($bugID > 0) + { + $oldBug = $this->loadModel('bug')->getById($bugID); + $productID = $oldBug->product; + $source = 'bug'; + $title = $oldBug->title; + $keywords = $oldBug->keywords; + $spec = $oldBug->steps; + $pri = $oldBug->pri; + $mailto = $oldBug->mailto; + } + + $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->create; + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name); + $this->view->position[] = $this->lang->story->create; + $this->view->products = $products; + $this->view->users = $users; + $this->view->moduleID = $moduleID; + $this->view->moduleOptionMenu = $moduleOptionMenu; + $this->view->plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired'); + $this->view->planID = $planID; + $this->view->source = $source; + $this->view->pri = $pri; + $this->view->productID = $productID; + $this->view->estimate = $estimate; + $this->view->title = $title; + $this->view->spec = $spec; + $this->view->verify = $verify; + $this->view->keywords = $keywords; + $this->view->mailto = $mailto; + + $this->display(); + } + + /** + * Create a batch stories. + * + * @param int $productID + * @param int $moduleID + * @access public + * @return void + */ + public function batchCreate($productID = 0, $moduleID = 0) + { + if(!empty($_POST)) + { + $mails = $this->story->batchCreate($productID); + if(dao::isError()) die(js::error(dao::getError())); + + foreach($mails as $mail) + { + $this->sendMail($mail->storyID, $mail->actionID); + } + die(js::locate($this->createLink('product', 'browse', "productID=$productID"), 'parent')); + } + + /* Set products, users and module. */ + $product = $this->product->getById($productID); + $products = $this->product->getPairs(); + $moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'story'); + + /* Set menu. */ + $this->product->setMenu($products, $product->id); + + /* Init vars. */ + $planID = 0; + $pri = 0; + $estimate = ''; + $title = ''; + $spec = ''; + + $moduleOptionMenu['same'] = $this->lang->story->same; + $plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired'); + $plans['same'] = $this->lang->story->same; + + $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->create; + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$productID"), $product->name); + $this->view->position[] = $this->lang->story->create; + $this->view->products = $products; + $this->view->moduleID = $moduleID; + $this->view->moduleOptionMenu = $moduleOptionMenu; + $this->view->plans = $plans; + $this->view->planID = $planID; + $this->view->pri = $pri; + $this->view->productID = $productID; + $this->view->estimate = $estimate; + $this->view->title = $title; + $this->view->spec = $spec; + + $this->display(); + } + + /** + * The common action when edit or change a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function commonAction($storyID) + { + /* Get datas. */ + $story = $this->story->getById($storyID); + $product = $this->product->getById($story->product); + $products = $this->product->getPairs(); + $users = $this->user->getPairs('nodeleted'); + $moduleOptionMenu = $this->tree->getOptionMenu($product->id, $viewType = 'story'); + + /* Set menu. */ + $this->product->setMenu($products, $product->id); + + /* Assign. */ + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); + $this->view->product = $product; + $this->view->products = $products; + $this->view->story = $story; + $this->view->users = $users; + $this->view->moduleOptionMenu = $moduleOptionMenu; + $this->view->plans = $this->loadModel('productplan')->getPairs($product->id); + $this->view->actions = $this->action->getList('story', $storyID); + } + + /** + * Edit a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function edit($storyID) + { + $this->loadModel('action'); + if(!empty($_POST)) + { + $changes = $this->story->update($storyID); + if(dao::isError()) die(js::error(dao::getError())); + if($this->post->comment != '' or !empty($changes)) + { + $action = !empty($changes) ? 'Edited' : 'Commented'; + $actionID = $this->action->create('story', $storyID, $action, $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendMail($storyID, $actionID); + } + die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); + } + + $this->commonAction($storyID); + + /* Assign. */ + $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->edit . $this->lang->colon . $this->view->story->title; + $this->view->position[] = $this->lang->story->edit; + $this->view->users = $this->user->appendDeleted($this->user->getPairs('nodeleted'), $this->view->story->assignedTo); + $this->display(); + } + + /** + * Change a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function change($storyID) + { + $this->loadModel('action'); + if(!empty($_POST)) + { + $changes = $this->story->change($storyID); + if(dao::isError()) die(js::error(dao::getError())); + $version = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch('version'); + $files = $this->loadModel('file')->saveUpload('story', $storyID, $version); + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $action = (!empty($changes) or !empty($files)) ? 'Changed' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; + $actionID = $this->action->create('story', $storyID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendMail($storyID, $actionID); + } + die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); + } + + $this->commonAction($storyID); + $this->story->getAffectedScope($this->view->story); + $this->app->loadLang('task'); + $this->app->loadLang('bug'); + $this->app->loadLang('testcase'); + $this->app->loadLang('project'); + + /* Assign. */ + $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->change . $this->lang->colon . $this->view->story->title; + $this->view->position[] = $this->lang->story->change; + $this->display(); + } + + /** + * Activate a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function activate($storyID) + { + $this->loadModel('action'); + if(!empty($_POST)) + { + $this->story->activate($storyID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('story', $storyID, 'Activated', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendMail($storyID, $actionID); + die(js::locate($this->createLink('story', 'view', "storyID=$storyID"), 'parent')); + } + + $this->commonAction($storyID); + + /* Assign. */ + $this->view->header->title = $this->view->product->name . $this->lang->colon . $this->lang->story->activate . $this->lang->colon . $this->view->story->title; + $this->view->position[] = $this->lang->story->activate; + $this->display(); + } + + /** + * View a story. + * + * @param int $storyID + * @param int $version + * @access public + * @return void + */ + public function view($storyID, $version = 0) + { + $this->loadModel('action'); + $storyID = (int)$storyID; + $story = $this->story->getById($storyID, $version); + if(!$story) die(js::error($this->lang->notFound) . js::locate('back')); + + $story->files = $this->loadModel('file')->getByObject('story', $storyID); + $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); + $plan = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title'); + $bugs = $this->dao->select('id,title')->from(TABLE_BUG)->where('story')->eq($storyID)->fetchAll(); + $fromBug = $this->dao->select('id,title')->from(TABLE_BUG)->where('toStory')->eq($storyID)->fetch(); + $cases = $this->dao->select('id,title')->from(TABLE_CASE)->where('story')->eq($storyID)->fetchAll(); + $modulePath = $this->tree->getParents($story->module); + $users = $this->user->getPairs('noletter'); + + /* Set the menu. */ + $this->product->setMenu($this->product->getPairs(), $product->id); + + $header['title'] = $product->name . $this->lang->colon . $this->lang->story->view . $this->lang->colon . $story->title; + $position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); + $position[] = $this->lang->story->view; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->product = $product; + $this->view->plan = $plan; + $this->view->bugs = $bugs; + $this->view->fromBug = $fromBug; + $this->view->cases = $cases; + $this->view->story = $story; + $this->view->users = $users; + $this->view->actions = $this->action->getList('story', $storyID); + $this->view->modulePath = $modulePath; + $this->view->version = $version == 0 ? $story->version : $version; + $this->display(); + } + + /** + * Delete a story. + * + * @param int $storyID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($storyID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->story->confirmDelete, $this->createLink('story', 'delete', "story=$storyID&confirm=yes"), ''); + exit; + } + else + { + $this->story->delete(TABLE_STORY, $storyID); + die(js::locate($this->session->storyList, 'parent')); + } + } + + /** + * Review a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function review($storyID) + { + $this->loadModel('action'); + + if(!empty($_POST)) + { + $this->story->review($storyID); + if(dao::isError()) die(js::error(dao::getError())); + $result = $this->post->result; + if($this->post->closedReason != '' and strpos('done,postponed,subdivided', $this->post->closedReason) !== false) $result = 'pass'; + $actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result)); + $this->action->logHistory($actionID, array()); + $this->sendMail($storyID, $actionID); + if($this->post->result == 'reject') + { + $this->action->create('story', $storyID, 'Closed', '', ucfirst($this->post->closedReason)); + } + die(js::locate(inlink('view', "storyID=$storyID"), 'parent')); + } + + /* Get story and product. */ + $story = $this->story->getById($storyID); + $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); + + /* Set menu. */ + $this->product->setMenu($this->product->getPairs(), $product->id); + + /* Set the review result options. */ + if($story->status == 'draft' and $story->version == 1) unset($this->lang->story->reviewResultList['revert']); + if($story->status == 'changed') unset($this->lang->story->reviewResultList['reject']); + + $this->view->header->title = $product->name . $this->lang->colon . $this->lang->story->view . $this->lang->colon . $story->title; + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); + $this->view->position[] = $this->lang->story->view; + + $this->view->product = $product; + $this->view->story = $story; + $this->view->actions = $this->action->getList('story', $storyID); + $this->view->users = $this->loadModel('user')->getPairs('nodeleted'); + + /* Get the affcected things. */ + $this->story->getAffectedScope($this->view->story); + $this->app->loadLang('task'); + $this->app->loadLang('bug'); + $this->app->loadLang('testcase'); + $this->app->loadLang('project'); + + $this->display(); + } + + /** + * Close a story. + * + * @param int $storyID + * @access public + * @return void + */ + public function close($storyID) + { + $this->loadModel('action'); + + if(!empty($_POST)) + { + $this->story->close($storyID); + if(dao::isError()) die(js::error(dao::getError())); + $actionID = $this->action->create('story', $storyID, 'Closed', $this->post->comment, ucfirst($this->post->closedReason)); + $this->action->logHistory($actionID); + $this->sendMail($storyID, $actionID); + die(js::locate(inlink('view', "storyID=$storyID"), 'parent')); + } + + /* Get story and product. */ + $story = $this->story->getById($storyID); + $product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fields('name, id')->fetch(); + + /* Set menu. */ + $this->product->setMenu($this->product->getPairs(), $product->id); + + /* Set the closed reason options. */ + if($story->status == 'draft') unset($this->lang->story->reasonList['cancel']); + + $this->view->header->title = $product->name . $this->lang->colon . $this->lang->close . $this->lang->colon . $story->title; + $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id"), $product->name); + $this->view->position[] = $this->lang->close; + + $this->view->product = $product; + $this->view->story = $story; + $this->view->actions = $this->action->getList('story', $storyID); + $this->view->users = $this->loadModel('user')->getPairs(); + $this->display(); + } + + /** + * Tasks of a story. + * + * @param int $storyID + * @param int $projectID + * @access public + * @return void + */ + public function tasks($storyID, $projectID = 0) + { + $this->loadModel('task'); + $this->view->tasks = $this->task->getStoryTaskPairs($storyID, $projectID); + $this->display(); + exit; + } + + /** + * AJAX: get stories of a project in html select. + * + * @param int $projectID + * @param int $productID + * @param int $storyID + * @access public + * @return void + */ + public function ajaxGetProjectStories($projectID, $productID = 0, $storyID = 0) + { + $stories = $this->story->getProjectStoryPairs($projectID, $productID); + die(html::select('story', $stories, $storyID)); + } + + /** + * AJAX: get stories of a product in html select. + * + * @param int $productID + * @param int $moduleID + * @param int $storyID + * @access public + * @return void + */ + public function ajaxGetProductStories($productID, $moduleID = 0, $storyID = 0) + { + $stories = $this->story->getProductStoryPairs($productID, $moduleID); + die(html::select('story', $stories, $storyID, "class=''")); + } + + /** + * Send email. + * + * @param int $storyID + * @param int $actionID + * @access public + * @return void + */ + public function sendmail($storyID, $actionID) + { + $story = $this->story->getById($storyID); + $productName = $this->product->getById($story->product)->name; + + /* Get actions. */ + $action = $this->loadModel('action')->getById($actionID); + $history = $this->action->getHistory($actionID); + $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); + if(strtolower($action->action) == 'opened') $action->comment = $story->spec; + + /* Set toList and ccList. */ + $toList = $story->assignedTo; + $ccList = str_replace(' ', '', trim($story->mailto, ',')); + + /* If the action is changed or reviewed, mail to the project team. */ + if(strtolower($action->action) == 'changed' or strtolower($action->action) == 'reviewed') + { + $prjMembers = $this->story->getProjectMembers($storyID); + if($prjMembers) + { + $ccList .= ',' . join(',', $prjMembers); + $ccList = ltrim($ccList, ','); + } + } + + if($toList == '') + { + if($ccList == '') return; + if(strpos($ccList, ',') === false) + { + $toList = $ccList; + $ccList = ''; + } + else + { + $commaPos = strpos($ccList, ','); + $toList = substr($ccList, 0, $commaPos); + $ccList = substr($ccList, $commaPos + 1); + } + } + elseif($toList == 'closed') + { + $toList = $story->openedBy; + } + + /* Get the mail content. */ + $this->view->story = $story; + $this->view->action = $action; + $this->view->users = $this->user->getPairs('noletter'); + $mailContent = $this->parse($this->moduleName, 'sendmail'); + + /* Send it. */ + $this->loadModel('mail')->send($toList, $productName . ':' . 'STORY #' . $story->id . $this->lang->colon . $story->title, $mailContent, $ccList); + if($this->mail->isError()) echo js::error($this->mail->getError()); + } + /** + * The report page. + * + * @param int $productID + * @param string $browseType + * @param int $moduleID + * @access public + * @return void + */ + public function report($productID, $browseType, $moduleID) + { + $this->loadModel('report'); + $this->view->charts = array(); + $this->view->renderJS = ''; + + if(!empty($_POST)) + { + foreach($this->post->charts as $chart) + { + $chartFunc = 'getDataOf' . $chart; + $chartData = $this->story->$chartFunc(); + $chartOption = $this->lang->story->report->$chart; + $this->story->mergeChartOption($chart); + + $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); + $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); + $this->view->datas[$chart] = $this->report->computePercent($chartData); + } + $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); + } + $this->products = $this->product->getPairs(); + $this->product->setMenu($this->products, $productID); + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->story->common; + $this->view->productID = $productID; + $this->view->browseType = $browseType; + $this->view->moduleID = $moduleID; + $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; + $this->display(); + } + + /** + * get data to export + * + * @param int $productID + * @param string $orderBy + * @access public + * @return void + */ + public function export($productID, $orderBy) + { + /* format the fields of every story in order to export data. */ + if($_POST) + { + $storyLang = $this->lang->story; + $storyConfig = $this->config->story; + + /* Create field lists. */ + $fields = explode(',', $storyConfig->list->exportFields); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($storyLang->$fieldName) ? $storyLang->$fieldName : $fieldName; + unset($fields[$key]); + } + + /* Get stories. */ + $stories = $this->dao->select('*')->from(TABLE_STORY)->where($this->session->storyReport)->orderBy($orderBy)->fetchAll('id'); + + /* Get users, products and projects. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $products = $this->loadModel('product')->getPairs(); + + /* Get related objects id lists. */ + $relatedModuleIdList = array(); + $relatedStoryIdList = array(); + $relatedPlanIdList = array(); + + foreach($stories as $story) + { + $relatedModuleIdList[$story->module] = $story->module; + $relatedPlanIdList[$story->plan] = $story->plan; + + /* Process related stories. */ + $relatedStories = $story->childStories . ',' . $story->linkStories . ',' . $story->duplicateStory; + $relatedStories = explode(',', $relatedStories); + foreach($relatedStories as $storyID) + { + if($storyID) $relatedStoryIdList[$storyID] = trim($storyID); + } + } + + /* Get related objects title or names. */ + $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); + $relatedPlans = $this->dao->select('id, title')->from(TABLE_PRODUCTPLAN)->where('id')->in($relatedPlanIdList)->fetchPairs(); + $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('story')->andWhere('objectID')->in(@array_keys($stories))->fetchGroup('objectID'); + $relatedSpecs = $this->dao->select('*')->from(TABLE_STORYSPEC)->where('`story`')->in(@array_keys($stories))->orderBy('version desc')->fetchGroup('story'); + + foreach($stories as $story) + { + $story->spec = ''; + $story->verify = ''; + if(isset($relatedSpecs[$story->id])) + { + $storySpec = $relatedSpecs[$story->id][0]; + $story->title = $storySpec->title; + $story->spec = $storySpec->spec; + $story->verify = $storySpec->verify; + } + + if($this->post->fileType == 'csv') + { + $story->spec = htmlspecialchars_decode($story->spec); + $story->spec = str_replace("
          ", "\n", $story->spec); + $story->spec = str_replace('"', '""', $story->spec); + + $story->verify = htmlspecialchars_decode($story->verify); + $story->verify = str_replace("
          ", "\n", $story->verify); + $story->verify = str_replace('"', '""', $story->verify); + } + + /* fill some field with useful value. */ + if(isset($products[$story->product])) $story->product = $products[$story->product]; + if(isset($relatedModules[$story->module])) $story->module = $relatedModules[$story->module]; + if(isset($relatedPlans[$story->plan])) $story->plan = $relatedPlans[$story->plan]; + if(isset($relatedStories[$story->duplicateStory])) $story->duplicateStory = $relatedStories[$story->duplicateStory]; + + if(isset($storyLang->priList[$story->pri])) $story->pri = $storyLang->priList[$story->pri]; + if(isset($storyLang->statusList[$story->status])) $story->status = $storyLang->statusList[$story->status]; + if(isset($storyLang->stageList[$story->stage])) $story->stage = $storyLang->stageList[$story->stage]; + if(isset($storyLang->reasonList[$story->closedReason])) $story->closedReason = $storyLang->reasonList[$story->closedReason]; + + if(isset($users[$story->openedBy])) $story->openedBy = $users[$story->openedBy]; + if(isset($users[$story->assignedTo])) $story->assignedTo = $users[$story->assignedTo]; + if(isset($users[$story->lastEditedBy])) $story->lastEditedBy = $users[$story->lastEditedBy]; + if(isset($users[$story->closedBy])) $story->closedBy = $users[$story->closedBy]; + + $story->openedDate = substr($story->openedDate, 0, 10); + $story->assignedDate = substr($story->assignedDate, 0, 10); + $story->lastEditedDate = substr($story->lastEditedDate, 0, 10); + $story->closedDate = substr($story->closedDate, 0, 10); + + + if($story->linkStories) + { + $tmpLinkStories = array(); + $linkStoriesIdList = explode(',', $story->linkStories); + foreach($linkStoriesIdList as $linkStoryID) + { + $linkStoryID = trim($linkStoryID); + $tmpLinkStories[] = isset($relatedStories[$linkStoryID]) ? $relatedStories[$linkStoryID] : $linkStoryID; + } + $story->linkStories = join("; \n", $tmpLinkStories); + } + + if($story->childStories) + { + $tmpChildStories = array(); + $childStoriesIdList = explode(',', $story->childStories); + foreach($childStoriesIdList as $childStoryID) + { + $childStoryID = trim($childStoryID); + $tmpChildStories[] = isset($relatedStories[$childStoryID]) ? $relatedStories[$childStoryID] : $childStoryID; + } + $story->childStories = join("; \n", $tmpChildStories); + } + + /* Set related files. */ + if(isset($relatedFiles[$story->id])) + { + foreach($relatedFiles[$story->id] as $file) + { + $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$story->company/" . $file->pathname; + $story->files .= html::a($fileURL, $file->title, '_blank') . '
          '; + } + } + + $story->mailto = trim(trim($story->mailto), ','); + $mailtos = explode(',', $story->mailto); + $story->mailto = ''; + foreach($mailtos as $mailto) + { + $mailto = trim($mailto); + if(isset($users[$mailto])) $story->mailto .= $users[$mailto] . ','; + } + + $story->reviewedBy = trim(trim($story->reviewedBy), ','); + $reviewedBys = explode(',', $story->reviewedBy); + $story->reviewedBy = ''; + foreach($reviewedBys as $reviewedBy) + { + $reviewedBy = trim($reviewedBy); + if(isset($users[$reviewedBy])) $story->reviewedBy .= $users[$reviewedBy] . ','; + } + + } + + $this->post->set('fields', $fields); + $this->post->set('rows', $stories); + $this->fetch('file', 'export2' . $this->post->fileType, $_POST); + } + + $this->display(); + } +} diff --git a/module/story/lang/en.php b/module/story/lang/en.php index 80d7ffa5e3..9f8d464017 100644 --- a/module/story/lang/en.php +++ b/module/story/lang/en.php @@ -1,222 +1,222 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->story->browse = "Browse"; -$lang->story->create = "Create"; -$lang->story->createCase = "Create case"; -$lang->story->batchCreate = "Batch create"; -$lang->story->change = "Change"; -$lang->story->changed = 'Changed'; -$lang->story->review = 'Review'; -$lang->story->edit = "Edit"; -$lang->story->close = 'Close'; -$lang->story->activate = 'Activate'; -$lang->story->delete = "Delete"; -$lang->story->view = "Info"; -$lang->story->tasks = "Tasks"; -$lang->story->taskCount = 'Tasks count'; -$lang->story->bugs = "Bug"; -$lang->story->linkStory = 'Related story'; -$lang->story->export = "Export"; -$lang->story->reportChart = "Report"; - -$lang->story->common = 'Story'; -$lang->story->id = 'ID'; -$lang->story->product = 'Product'; -$lang->story->module = 'Module'; -$lang->story->source = 'Source'; -$lang->story->release = 'Release'; -$lang->story->bug = 'Related Bug'; -$lang->story->title = 'Title'; -$lang->story->spec = 'Spec'; -$lang->story->verify = 'Verify'; -$lang->story->type = 'Type '; -$lang->story->pri = 'Priority'; -$lang->story->estimate = 'Estimate'; -$lang->story->estimateAB = 'Estimate'; -$lang->story->status = 'Status'; -$lang->story->stage = 'Stage'; -$lang->story->stageAB = 'Stage'; -$lang->story->mailto = 'Mailto'; -$lang->story->openedBy = 'Opened by'; -$lang->story->openedDate = 'Opened date'; -$lang->story->assignedTo = 'Assigned to'; -$lang->story->assignedDate = 'Assigned date'; -$lang->story->lastEditedBy = 'Last edited by'; -$lang->story->lastEditedDate = 'Last edited date'; -$lang->story->lastEdited = 'Last edited'; -$lang->story->closedBy = 'Closed by'; -$lang->story->closedDate = 'Closed date'; -$lang->story->closedReason = 'Closed reason'; -$lang->story->rejectedReason = 'Reject reason'; -$lang->story->reviewedBy = 'Reviewed by'; -$lang->story->reviewedDate = 'Reviewed date'; -$lang->story->version = 'Version'; -$lang->story->project = 'Project'; -$lang->story->plan = 'Plan'; -$lang->story->planAB = 'Plan'; -$lang->story->comment = 'Comment'; -$lang->story->linkStories = 'Related story'; -$lang->story->childStories = 'Child story'; -$lang->story->duplicateStory = 'Duplicate story'; -$lang->story->reviewResult = 'Reviewed result'; -$lang->story->preVersion = 'Pre version'; -$lang->story->keywords = 'Keyword'; - -$lang->story->same = 'The same as above'; - -$lang->story->useList[0] = 'No use'; -$lang->story->useList[1] = 'Use'; - -$lang->story->statusList[''] = ''; -$lang->story->statusList['draft'] = 'Draft'; -$lang->story->statusList['active'] = 'Active'; -$lang->story->statusList['closed'] = 'Closed'; -$lang->story->statusList['changed'] = 'Changed'; - -$lang->story->stageList[''] = ''; -$lang->story->stageList['wait'] = 'Waitting'; -$lang->story->stageList['planned'] = 'Planned'; -$lang->story->stageList['projected'] = 'Projected'; -$lang->story->stageList['developing'] = 'Developing'; -$lang->story->stageList['developed'] = 'Developed'; -$lang->story->stageList['testing'] = 'Testing'; -$lang->story->stageList['tested'] = 'Tested'; -$lang->story->stageList['verified'] = 'Verified'; -$lang->story->stageList['released'] = 'Released'; - -$lang->story->reasonList[''] = ''; -$lang->story->reasonList['done'] = 'Done'; -$lang->story->reasonList['subdivided'] = 'Subdivided'; -$lang->story->reasonList['duplicate'] = 'Duplicate'; -$lang->story->reasonList['postponed'] = 'Postponed'; -$lang->story->reasonList['willnotdo'] = "Won't do"; -$lang->story->reasonList['cancel'] = 'Canceled'; -$lang->story->reasonList['bydesign'] = 'By design'; -//$lang->story->reasonList['isbug'] = '是个Bug'; - -$lang->story->reviewResultList[''] = ''; -$lang->story->reviewResultList['pass'] = 'Pass'; -$lang->story->reviewResultList['revert'] = 'Revert'; -$lang->story->reviewResultList['clarify'] = 'Clarify'; -$lang->story->reviewResultList['reject'] = 'Reject'; - -$lang->story->reviewList[0] = 'No'; -$lang->story->reviewList[1] = 'Yes'; - -$lang->story->sourceList[''] = ''; -$lang->story->sourceList['customer'] = 'Customer'; -$lang->story->sourceList['user'] = 'User'; -$lang->story->sourceList['po'] = 'Product Owner'; -$lang->story->sourceList['market'] = 'Market'; -$lang->story->sourceList['service'] = 'Customer service'; -$lang->story->sourceList['competitor'] = 'Competitor'; -$lang->story->sourceList['partner'] = 'Partner'; -$lang->story->sourceList['dev'] = 'Developer'; -$lang->story->sourceList['tester'] = 'Tester'; -$lang->story->sourceList['bug'] = 'Bug'; -$lang->story->sourceList['other'] = 'Other'; - -$lang->story->priList[] = ''; -$lang->story->priList[3] = '3'; -$lang->story->priList[1] = '1'; -$lang->story->priList[2] = '2'; -$lang->story->priList[4] = '4'; - -$lang->story->legendBasicInfo = 'Basic info'; -$lang->story->legendLifeTime = 'Life time'; -$lang->story->legendRelated = 'Related info'; -$lang->story->legendMailto = 'Maitto'; -$lang->story->legendAttatch = 'Files'; -$lang->story->legendProjectAndTask = 'Project & task'; -$lang->story->legendBugs = 'Related Bug'; -$lang->story->legendFromBug = 'From Bug'; -$lang->story->legendCases = 'Related Case'; -$lang->story->legendLinkStories = 'Related story'; -$lang->story->legendChildStories = 'Child story'; -$lang->story->legendSpec = 'Spec'; -$lang->story->legendVerify = 'Verify standard'; -$lang->story->legendHistory = 'History'; -$lang->story->legendVersion = 'Versions'; -$lang->story->legendMisc = 'Misc'; - -$lang->story->lblChange = 'Change'; -$lang->story->lblReview = 'Review'; -$lang->story->lblActivate = 'Activate'; -$lang->story->lblClose = 'Close'; - -$lang->story->affectedProjects = 'Affected projects'; -$lang->story->affectedBugs = 'Affected bugs'; -$lang->story->affectedCases = 'Affected cases'; - -$lang->story->specTemplate = "Recommend template::As <a type of user>,I want <some goals>,so that <some reason>."; -$lang->story->notes = "(notes:if the title is empty, it is no use)"; -$lang->story->needNotReview = "needn't review"; -$lang->story->confirmDelete = "Are you sure to delete this story?"; -$lang->story->errorFormat = 'Error format'; -$lang->story->errorEmptyTitle = "Title can't be empty"; -$lang->story->mustChooseResult = 'Must choose s result'; -$lang->story->mustChoosePreVersion = 'Must select an version to revert'; -$lang->story->ajaxGetProjectStories = 'API:Project stories'; -$lang->story->ajaxGetProductStories = 'API:Product stories'; - -$lang->story->action->reviewed = array('main' => '$date, Reviewed by $actor, result is $extra.', 'extra' => $lang->story->reviewResultList); -$lang->story->action->closed = array('main' => '$date, Closed by $actor, reason is $extra.', 'extra' => $lang->story->reasonList); -$lang->story->action->linked2plan = array('main' => '$date, Linked to plan $extra by $actor.'); -$lang->story->action->unlinkedfromplan = array('main' => '$date, Removed from $extra> by $actor'); -$lang->story->action->linked2project = array('main' => '$date, Linked to project $extra by $actor.'); -$lang->story->action->unlinkedfromproject = array('main' => '$date, Removed from project $extra by $actor.'); - -/* Report*/ -$lang->story->report->common = 'Report'; -$lang->story->report->select = 'Select'; -$lang->story->report->create = 'Creat'; -$lang->story->report->selectAll = 'All'; -$lang->story->report->selectReverse = 'Reverse'; - -$lang->story->report->charts['storysPerProduct'] = 'Product storys'; -$lang->story->report->charts['storysPerModule'] = 'Module storys'; -$lang->story->report->charts['storysPerSource'] = 'Source storys'; -$lang->story->report->charts['storysPerPlan'] = 'Plan storys'; -$lang->story->report->charts['storysPerStatus'] = 'Sotrys of status'; -$lang->story->report->charts['storysPerStage'] = 'Storys of stage'; -$lang->story->report->charts['storysPerPri'] = 'Storys of priority'; -$lang->story->report->charts['storysPerEstimate'] = 'Storys of Estimate'; -$lang->story->report->charts['storysPerOpenedBy'] = 'Opened by user'; -$lang->story->report->charts['storysPerAssignedTo'] = 'Assigned to user'; -$lang->story->report->charts['storysPerClosedReason'] = 'Storys for reason'; -$lang->story->report->charts['storysPerChange'] = 'Story version'; - -$lang->story->report->options->swf = 'pie2d'; -$lang->story->report->options->width = 'auto'; -$lang->story->report->options->height = 300; -$lang->story->report->options->graph->baseFontSize = 12; -$lang->story->report->options->graph->showNames = 1; -$lang->story->report->options->graph->formatNumber = 1; -$lang->story->report->options->graph->decimalPrecision = 0; -$lang->story->report->options->graph->animation = 0; -$lang->story->report->options->graph->rotateNames = 0; -$lang->story->report->options->graph->yAxisName = 'COUNT'; -$lang->story->report->options->graph->pieRadius = 100; -$lang->story->report->options->graph->showColumnShadow = 0; - -$lang->story->report->storysPerProduct->graph->xAxisName = 'Product'; -$lang->story->report->storysPerModule->graph->xAxisName = 'Module'; -$lang->story->report->storysPerSource->graph->xAxisName = 'Source'; -$lang->story->report->storysPerPlan->graph->xAxisName = 'Plan'; -$lang->story->report->storysPerStatus->graph->xAxisName = 'Status'; -$lang->story->report->storysPerStage->graph->xAxisName = 'Stage'; -$lang->story->report->storysPerPri->graph->xAxisName = 'Priority'; -$lang->story->report->storysPerOpenedBy->graph->xAxisName = 'Opened by'; -$lang->story->report->storysPerAssignedTo->graph->xAxisName = 'Assigned to'; -$lang->story->report->storysPerClosedReason->graph->xAxisName = 'Closed reason'; -$lang->story->report->storysPerEstimate->graph->xAxisName = 'Estimate'; -$lang->story->report->storysPerChange->graph->xAxisName = 'Change'; + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->story->browse = "Browse"; +$lang->story->create = "Create"; +$lang->story->createCase = "Create case"; +$lang->story->batchCreate = "Batch create"; +$lang->story->change = "Change"; +$lang->story->changed = 'Changed'; +$lang->story->review = 'Review'; +$lang->story->edit = "Edit"; +$lang->story->close = 'Close'; +$lang->story->activate = 'Activate'; +$lang->story->delete = "Delete"; +$lang->story->view = "Info"; +$lang->story->tasks = "Tasks"; +$lang->story->taskCount = 'Tasks count'; +$lang->story->bugs = "Bug"; +$lang->story->linkStory = 'Related story'; +$lang->story->export = "Export"; +$lang->story->reportChart = "Report"; + +$lang->story->common = 'Story'; +$lang->story->id = 'ID'; +$lang->story->product = 'Product'; +$lang->story->module = 'Module'; +$lang->story->source = 'Source'; +$lang->story->release = 'Release'; +$lang->story->bug = 'Related Bug'; +$lang->story->title = 'Title'; +$lang->story->spec = 'Spec'; +$lang->story->verify = 'Verify'; +$lang->story->type = 'Type '; +$lang->story->pri = 'Priority'; +$lang->story->estimate = 'Estimate'; +$lang->story->estimateAB = 'Estimate'; +$lang->story->status = 'Status'; +$lang->story->stage = 'Stage'; +$lang->story->stageAB = 'Stage'; +$lang->story->mailto = 'Mailto'; +$lang->story->openedBy = 'Opened by'; +$lang->story->openedDate = 'Opened date'; +$lang->story->assignedTo = 'Assigned to'; +$lang->story->assignedDate = 'Assigned date'; +$lang->story->lastEditedBy = 'Last edited by'; +$lang->story->lastEditedDate = 'Last edited date'; +$lang->story->lastEdited = 'Last edited'; +$lang->story->closedBy = 'Closed by'; +$lang->story->closedDate = 'Closed date'; +$lang->story->closedReason = 'Closed reason'; +$lang->story->rejectedReason = 'Reject reason'; +$lang->story->reviewedBy = 'Reviewed by'; +$lang->story->reviewedDate = 'Reviewed date'; +$lang->story->version = 'Version'; +$lang->story->project = 'Project'; +$lang->story->plan = 'Plan'; +$lang->story->planAB = 'Plan'; +$lang->story->comment = 'Comment'; +$lang->story->linkStories = 'Related story'; +$lang->story->childStories = 'Child story'; +$lang->story->duplicateStory = 'Duplicate story'; +$lang->story->reviewResult = 'Reviewed result'; +$lang->story->preVersion = 'Pre version'; +$lang->story->keywords = 'Keyword'; + +$lang->story->same = 'The same as above'; + +$lang->story->useList[0] = 'No use'; +$lang->story->useList[1] = 'Use'; + +$lang->story->statusList[''] = ''; +$lang->story->statusList['draft'] = 'Draft'; +$lang->story->statusList['active'] = 'Active'; +$lang->story->statusList['closed'] = 'Closed'; +$lang->story->statusList['changed'] = 'Changed'; + +$lang->story->stageList[''] = ''; +$lang->story->stageList['wait'] = 'Waitting'; +$lang->story->stageList['planned'] = 'Planned'; +$lang->story->stageList['projected'] = 'Projected'; +$lang->story->stageList['developing'] = 'Developing'; +$lang->story->stageList['developed'] = 'Developed'; +$lang->story->stageList['testing'] = 'Testing'; +$lang->story->stageList['tested'] = 'Tested'; +$lang->story->stageList['verified'] = 'Verified'; +$lang->story->stageList['released'] = 'Released'; + +$lang->story->reasonList[''] = ''; +$lang->story->reasonList['done'] = 'Done'; +$lang->story->reasonList['subdivided'] = 'Subdivided'; +$lang->story->reasonList['duplicate'] = 'Duplicate'; +$lang->story->reasonList['postponed'] = 'Postponed'; +$lang->story->reasonList['willnotdo'] = "Won't do"; +$lang->story->reasonList['cancel'] = 'Canceled'; +$lang->story->reasonList['bydesign'] = 'By design'; +//$lang->story->reasonList['isbug'] = '是个Bug'; + +$lang->story->reviewResultList[''] = ''; +$lang->story->reviewResultList['pass'] = 'Pass'; +$lang->story->reviewResultList['revert'] = 'Revert'; +$lang->story->reviewResultList['clarify'] = 'Clarify'; +$lang->story->reviewResultList['reject'] = 'Reject'; + +$lang->story->reviewList[0] = 'No'; +$lang->story->reviewList[1] = 'Yes'; + +$lang->story->sourceList[''] = ''; +$lang->story->sourceList['customer'] = 'Customer'; +$lang->story->sourceList['user'] = 'User'; +$lang->story->sourceList['po'] = 'Product Owner'; +$lang->story->sourceList['market'] = 'Market'; +$lang->story->sourceList['service'] = 'Customer service'; +$lang->story->sourceList['competitor'] = 'Competitor'; +$lang->story->sourceList['partner'] = 'Partner'; +$lang->story->sourceList['dev'] = 'Developer'; +$lang->story->sourceList['tester'] = 'Tester'; +$lang->story->sourceList['bug'] = 'Bug'; +$lang->story->sourceList['other'] = 'Other'; + +$lang->story->priList[] = ''; +$lang->story->priList[3] = '3'; +$lang->story->priList[1] = '1'; +$lang->story->priList[2] = '2'; +$lang->story->priList[4] = '4'; + +$lang->story->legendBasicInfo = 'Basic info'; +$lang->story->legendLifeTime = 'Life time'; +$lang->story->legendRelated = 'Related info'; +$lang->story->legendMailto = 'Maitto'; +$lang->story->legendAttatch = 'Files'; +$lang->story->legendProjectAndTask = 'Project & task'; +$lang->story->legendBugs = 'Related Bug'; +$lang->story->legendFromBug = 'From Bug'; +$lang->story->legendCases = 'Related Case'; +$lang->story->legendLinkStories = 'Related story'; +$lang->story->legendChildStories = 'Child story'; +$lang->story->legendSpec = 'Spec'; +$lang->story->legendVerify = 'Verify standard'; +$lang->story->legendHistory = 'History'; +$lang->story->legendVersion = 'Versions'; +$lang->story->legendMisc = 'Misc'; + +$lang->story->lblChange = 'Change'; +$lang->story->lblReview = 'Review'; +$lang->story->lblActivate = 'Activate'; +$lang->story->lblClose = 'Close'; + +$lang->story->affectedProjects = 'Affected projects'; +$lang->story->affectedBugs = 'Affected bugs'; +$lang->story->affectedCases = 'Affected cases'; + +$lang->story->specTemplate = "Recommend template::As <a type of user>,I want <some goals>,so that <some reason>."; +$lang->story->notes = "(notes:if the title is empty, it is no use)"; +$lang->story->needNotReview = "needn't review"; +$lang->story->confirmDelete = "Are you sure to delete this story?"; +$lang->story->errorFormat = 'Error format'; +$lang->story->errorEmptyTitle = "Title can't be empty"; +$lang->story->mustChooseResult = 'Must choose s result'; +$lang->story->mustChoosePreVersion = 'Must select an version to revert'; +$lang->story->ajaxGetProjectStories = 'API:Project stories'; +$lang->story->ajaxGetProductStories = 'API:Product stories'; + +$lang->story->action->reviewed = array('main' => '$date, Reviewed by $actor, result is $extra.', 'extra' => $lang->story->reviewResultList); +$lang->story->action->closed = array('main' => '$date, Closed by $actor, reason is $extra.', 'extra' => $lang->story->reasonList); +$lang->story->action->linked2plan = array('main' => '$date, Linked to plan $extra by $actor.'); +$lang->story->action->unlinkedfromplan = array('main' => '$date, Removed from $extra> by $actor'); +$lang->story->action->linked2project = array('main' => '$date, Linked to project $extra by $actor.'); +$lang->story->action->unlinkedfromproject = array('main' => '$date, Removed from project $extra by $actor.'); + +/* Report*/ +$lang->story->report->common = 'Report'; +$lang->story->report->select = 'Select'; +$lang->story->report->create = 'Creat'; +$lang->story->report->selectAll = 'All'; +$lang->story->report->selectReverse = 'Reverse'; + +$lang->story->report->charts['storysPerProduct'] = 'Product storys'; +$lang->story->report->charts['storysPerModule'] = 'Module storys'; +$lang->story->report->charts['storysPerSource'] = 'Source storys'; +$lang->story->report->charts['storysPerPlan'] = 'Plan storys'; +$lang->story->report->charts['storysPerStatus'] = 'Sotrys of status'; +$lang->story->report->charts['storysPerStage'] = 'Storys of stage'; +$lang->story->report->charts['storysPerPri'] = 'Storys of priority'; +$lang->story->report->charts['storysPerEstimate'] = 'Storys of Estimate'; +$lang->story->report->charts['storysPerOpenedBy'] = 'Opened by user'; +$lang->story->report->charts['storysPerAssignedTo'] = 'Assigned to user'; +$lang->story->report->charts['storysPerClosedReason'] = 'Storys for reason'; +$lang->story->report->charts['storysPerChange'] = 'Story version'; + +$lang->story->report->options->swf = 'pie2d'; +$lang->story->report->options->width = 'auto'; +$lang->story->report->options->height = 300; +$lang->story->report->options->graph->baseFontSize = 12; +$lang->story->report->options->graph->showNames = 1; +$lang->story->report->options->graph->formatNumber = 1; +$lang->story->report->options->graph->decimalPrecision = 0; +$lang->story->report->options->graph->animation = 0; +$lang->story->report->options->graph->rotateNames = 0; +$lang->story->report->options->graph->yAxisName = 'COUNT'; +$lang->story->report->options->graph->pieRadius = 100; +$lang->story->report->options->graph->showColumnShadow = 0; + +$lang->story->report->storysPerProduct->graph->xAxisName = 'Product'; +$lang->story->report->storysPerModule->graph->xAxisName = 'Module'; +$lang->story->report->storysPerSource->graph->xAxisName = 'Source'; +$lang->story->report->storysPerPlan->graph->xAxisName = 'Plan'; +$lang->story->report->storysPerStatus->graph->xAxisName = 'Status'; +$lang->story->report->storysPerStage->graph->xAxisName = 'Stage'; +$lang->story->report->storysPerPri->graph->xAxisName = 'Priority'; +$lang->story->report->storysPerOpenedBy->graph->xAxisName = 'Opened by'; +$lang->story->report->storysPerAssignedTo->graph->xAxisName = 'Assigned to'; +$lang->story->report->storysPerClosedReason->graph->xAxisName = 'Closed reason'; +$lang->story->report->storysPerEstimate->graph->xAxisName = 'Estimate'; +$lang->story->report->storysPerChange->graph->xAxisName = 'Change'; diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index 55856a3736..bdb87e07e2 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -1,222 +1,222 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->story->browse = "需求列表"; -$lang->story->create = "新增需求"; -$lang->story->createCase = "建用例"; -$lang->story->batchCreate = "批量添加"; -$lang->story->change = "变更"; -$lang->story->changed = '需求变更'; -$lang->story->review = '评审'; -$lang->story->edit = "编辑需求"; -$lang->story->close = '关闭'; -$lang->story->activate = '激活'; -$lang->story->delete = "删除需求"; -$lang->story->view = "需求详情"; -$lang->story->tasks = "相关任务"; -$lang->story->taskCount = '任务数'; -$lang->story->bugs = "Bug"; -$lang->story->linkStory = '关联需求'; -$lang->story->export = "导出数据"; -$lang->story->reportChart = "统计报表"; - -$lang->story->common = '需求'; -$lang->story->id = '编号'; -$lang->story->product = '所属产品'; -$lang->story->module = '所属模块'; -$lang->story->source = '来源'; -$lang->story->release = '发布计划'; -$lang->story->bug = '相关bug'; -$lang->story->title = '需求名称'; -$lang->story->spec = '需求描述'; -$lang->story->verify = '验收标准'; -$lang->story->type = '需求类型 '; -$lang->story->pri = '优先级'; -$lang->story->estimate = '预计工时'; -$lang->story->estimateAB = '预计'; -$lang->story->status = '当前状态'; -$lang->story->stage = '所处阶段'; -$lang->story->stageAB = '阶段'; -$lang->story->mailto = '抄送给'; -$lang->story->openedBy = '由谁创建'; -$lang->story->openedDate = '创建日期'; -$lang->story->assignedTo = '指派给'; -$lang->story->assignedDate = '指派日期'; -$lang->story->lastEditedBy = '最后修改'; -$lang->story->lastEditedDate = '最后修改日期'; -$lang->story->lastEdited = '最后修改'; -$lang->story->closedBy = '由谁关闭'; -$lang->story->closedDate = '关闭日期'; -$lang->story->closedReason = '关闭原因'; -$lang->story->rejectedReason = '拒绝原因'; -$lang->story->reviewedBy = '由谁评审'; -$lang->story->reviewedDate = '评审时间'; -$lang->story->version = '版本号'; -$lang->story->project = '所属项目'; -$lang->story->plan = '所属计划'; -$lang->story->planAB = '计划'; -$lang->story->comment = '备注'; -$lang->story->linkStories = '相关需求'; -$lang->story->childStories = '细分需求'; -$lang->story->duplicateStory = '重复需求'; -$lang->story->reviewResult = '评审结果'; -$lang->story->preVersion = '之前版本'; -$lang->story->keywords = '关键词'; - -$lang->story->same = '同上'; - -$lang->story->useList[0] = '不使用'; -$lang->story->useList[1] = '使用'; - -$lang->story->statusList[''] = ''; -$lang->story->statusList['draft'] = '草稿'; -$lang->story->statusList['active'] = '激活'; -$lang->story->statusList['closed'] = '已关闭'; -$lang->story->statusList['changed'] = '已变更'; - -$lang->story->stageList[''] = ''; -$lang->story->stageList['wait'] = '未开始'; -$lang->story->stageList['planned'] = '已计划'; -$lang->story->stageList['projected'] = '已立项'; -$lang->story->stageList['developing'] = '研发中'; -$lang->story->stageList['developed'] = '研发完毕'; -$lang->story->stageList['testing'] = '测试中'; -$lang->story->stageList['tested'] = '测试完毕'; -$lang->story->stageList['verified'] = '已验收'; -$lang->story->stageList['released'] = '已发布'; - -$lang->story->reasonList[''] = ''; -$lang->story->reasonList['done'] = '已完成'; -$lang->story->reasonList['subdivided'] = '已细分'; -$lang->story->reasonList['duplicate'] = '重复'; -$lang->story->reasonList['postponed'] = '延期'; -$lang->story->reasonList['willnotdo'] = '不做'; -$lang->story->reasonList['cancel'] = '已取消'; -$lang->story->reasonList['bydesign'] = '设计如此'; -//$lang->story->reasonList['isbug'] = '是个Bug'; - -$lang->story->reviewResultList[''] = ''; -$lang->story->reviewResultList['pass'] = '确认通过'; -$lang->story->reviewResultList['revert'] = '撤销变更'; -$lang->story->reviewResultList['clarify'] = '有待明确'; -$lang->story->reviewResultList['reject'] = '拒绝'; - -$lang->story->reviewList[0] = '否'; -$lang->story->reviewList[1] = '是'; - -$lang->story->sourceList[''] = ''; -$lang->story->sourceList['customer'] = '客户'; -$lang->story->sourceList['user'] = '用户'; -$lang->story->sourceList['po'] = '产品经理'; -$lang->story->sourceList['market'] = '市场'; -$lang->story->sourceList['service'] = '客服'; -$lang->story->sourceList['competitor'] = '竞争对手'; -$lang->story->sourceList['partner'] = '合作伙伴'; -$lang->story->sourceList['dev'] = '开发人员'; -$lang->story->sourceList['tester'] = '测试人员'; -$lang->story->sourceList['bug'] = 'Bug'; -$lang->story->sourceList['other'] = '其他'; - -$lang->story->priList[] = ''; -$lang->story->priList[3] = '3'; -$lang->story->priList[1] = '1'; -$lang->story->priList[2] = '2'; -$lang->story->priList[4] = '4'; - -$lang->story->legendBasicInfo = '基本信息'; -$lang->story->legendLifeTime = '需求的一生'; -$lang->story->legendRelated = '相关信息'; -$lang->story->legendMailto = '抄送给'; -$lang->story->legendAttatch = '附件'; -$lang->story->legendProjectAndTask = '项目任务'; -$lang->story->legendBugs = '相关Bug'; -$lang->story->legendFromBug = '来源Bug'; -$lang->story->legendCases = '相关用例'; -$lang->story->legendLinkStories = '相关需求'; -$lang->story->legendChildStories = '细分需求'; -$lang->story->legendSpec = '需求描述'; -$lang->story->legendVerify = '验收标准'; -$lang->story->legendHistory = '历史记录'; -$lang->story->legendVersion = '历史版本'; -$lang->story->legendMisc = '其他相关'; - -$lang->story->lblChange = '变更需求'; -$lang->story->lblReview = '评审需求'; -$lang->story->lblActivate = '激活需求'; -$lang->story->lblClose = '关闭需求'; - -$lang->story->affectedProjects = '影响的项目'; -$lang->story->affectedBugs = '影响的Bug'; -$lang->story->affectedCases = '影响的用例'; - -$lang->story->specTemplate = "建议参考的模板:作为一名<某种类型的用户>,我希望<达成某些目的>,这样可以<开发的价值>。"; -$lang->story->notes = '(注:如果“需求标题”为空,则表示不使用此行)'; -$lang->story->needNotReview = '不需要评审'; -$lang->story->confirmDelete = "您确认删除该需求吗?"; -$lang->story->errorFormat = '需求数据有误'; -$lang->story->errorEmptyTitle = '标题不能为空'; -$lang->story->mustChooseResult = '必须选择评审结果'; -$lang->story->mustChoosePreVersion = '必须选择回溯的版本'; -$lang->story->ajaxGetProjectStories = '接口:获取项目需求列表'; -$lang->story->ajaxGetProductStories = '接口:获取产品需求列表'; - -$lang->story->action->reviewed = array('main' => '$date, 由 $actor 记录评审结果,结果为 $extra。', 'extra' => $lang->story->reviewResultList); -$lang->story->action->closed = array('main' => '$date, 由 $actor 关闭,原因为 $extra。', 'extra' => $lang->story->reasonList); -$lang->story->action->linked2plan = array('main' => '$date, 由 $actor 关联到计划 $extra。'); -$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 从计划 $extra 移除。'); -$lang->story->action->linked2project = array('main' => '$date, 由 $actor 关联到项目 $extra。'); -$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 $actor 从项目 $extra 移除。'); - -/* 统计报表。*/ -$lang->story->report->common = '统计报表'; -$lang->story->report->select = '请选择报表类型'; -$lang->story->report->create = '生成报表'; -$lang->story->report->selectAll = '全选'; -$lang->story->report->selectReverse = '反选'; - -$lang->story->report->charts['storysPerProduct'] = '产品需求数量'; -$lang->story->report->charts['storysPerModule'] = '模块需求数量'; -$lang->story->report->charts['storysPerSource'] = '需求来源统计'; -$lang->story->report->charts['storysPerPlan'] = '计划进行统计'; -$lang->story->report->charts['storysPerStatus'] = '状态进行统计'; -$lang->story->report->charts['storysPerStage'] = '所处阶段进行统计'; -$lang->story->report->charts['storysPerPri'] = '优先级进行统计'; -$lang->story->report->charts['storysPerEstimate'] = '预计工时进行统计'; -$lang->story->report->charts['storysPerOpenedBy'] = '由谁创建来进行统计'; -$lang->story->report->charts['storysPerAssignedTo'] = '当前指派来进行统计'; -$lang->story->report->charts['storysPerClosedReason'] = '关闭原因来进行统计'; -$lang->story->report->charts['storysPerChange'] = '变更次数来进行统计'; - -$lang->story->report->options->swf = 'pie2d'; -$lang->story->report->options->width = 'auto'; -$lang->story->report->options->height = 300; -$lang->story->report->options->graph->baseFontSize = 12; -$lang->story->report->options->graph->showNames = 1; -$lang->story->report->options->graph->formatNumber = 1; -$lang->story->report->options->graph->decimalPrecision = 0; -$lang->story->report->options->graph->animation = 0; -$lang->story->report->options->graph->rotateNames = 0; -$lang->story->report->options->graph->yAxisName = 'COUNT'; -$lang->story->report->options->graph->pieRadius = 100; // 饼图直径。 -$lang->story->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 - -$lang->story->report->storysPerProduct->graph->xAxisName = '产品'; -$lang->story->report->storysPerModule->graph->xAxisName = '模块'; -$lang->story->report->storysPerSource->graph->xAxisName = '来源'; -$lang->story->report->storysPerPlan->graph->xAxisName = '产品计划'; -$lang->story->report->storysPerStatus->graph->xAxisName = '状态'; -$lang->story->report->storysPerStage->graph->xAxisName = '所处阶段'; -$lang->story->report->storysPerPri->graph->xAxisName = '优先级'; -$lang->story->report->storysPerOpenedBy->graph->xAxisName = '由谁创建'; -$lang->story->report->storysPerAssignedTo->graph->xAxisName = '当前指派'; -$lang->story->report->storysPerClosedReason->graph->xAxisName = '关闭原因'; -$lang->story->report->storysPerEstimate->graph->xAxisName = '预计时间'; -$lang->story->report->storysPerChange->graph->xAxisName = '变更次数'; + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->story->browse = "需求列表"; +$lang->story->create = "新增需求"; +$lang->story->createCase = "建用例"; +$lang->story->batchCreate = "批量添加"; +$lang->story->change = "变更"; +$lang->story->changed = '需求变更'; +$lang->story->review = '评审'; +$lang->story->edit = "编辑需求"; +$lang->story->close = '关闭'; +$lang->story->activate = '激活'; +$lang->story->delete = "删除需求"; +$lang->story->view = "需求详情"; +$lang->story->tasks = "相关任务"; +$lang->story->taskCount = '任务数'; +$lang->story->bugs = "Bug"; +$lang->story->linkStory = '关联需求'; +$lang->story->export = "导出数据"; +$lang->story->reportChart = "统计报表"; + +$lang->story->common = '需求'; +$lang->story->id = '编号'; +$lang->story->product = '所属产品'; +$lang->story->module = '所属模块'; +$lang->story->source = '来源'; +$lang->story->release = '发布计划'; +$lang->story->bug = '相关bug'; +$lang->story->title = '需求名称'; +$lang->story->spec = '需求描述'; +$lang->story->verify = '验收标准'; +$lang->story->type = '需求类型 '; +$lang->story->pri = '优先级'; +$lang->story->estimate = '预计工时'; +$lang->story->estimateAB = '预计'; +$lang->story->status = '当前状态'; +$lang->story->stage = '所处阶段'; +$lang->story->stageAB = '阶段'; +$lang->story->mailto = '抄送给'; +$lang->story->openedBy = '由谁创建'; +$lang->story->openedDate = '创建日期'; +$lang->story->assignedTo = '指派给'; +$lang->story->assignedDate = '指派日期'; +$lang->story->lastEditedBy = '最后修改'; +$lang->story->lastEditedDate = '最后修改日期'; +$lang->story->lastEdited = '最后修改'; +$lang->story->closedBy = '由谁关闭'; +$lang->story->closedDate = '关闭日期'; +$lang->story->closedReason = '关闭原因'; +$lang->story->rejectedReason = '拒绝原因'; +$lang->story->reviewedBy = '由谁评审'; +$lang->story->reviewedDate = '评审时间'; +$lang->story->version = '版本号'; +$lang->story->project = '所属项目'; +$lang->story->plan = '所属计划'; +$lang->story->planAB = '计划'; +$lang->story->comment = '备注'; +$lang->story->linkStories = '相关需求'; +$lang->story->childStories = '细分需求'; +$lang->story->duplicateStory = '重复需求'; +$lang->story->reviewResult = '评审结果'; +$lang->story->preVersion = '之前版本'; +$lang->story->keywords = '关键词'; + +$lang->story->same = '同上'; + +$lang->story->useList[0] = '不使用'; +$lang->story->useList[1] = '使用'; + +$lang->story->statusList[''] = ''; +$lang->story->statusList['draft'] = '草稿'; +$lang->story->statusList['active'] = '激活'; +$lang->story->statusList['closed'] = '已关闭'; +$lang->story->statusList['changed'] = '已变更'; + +$lang->story->stageList[''] = ''; +$lang->story->stageList['wait'] = '未开始'; +$lang->story->stageList['planned'] = '已计划'; +$lang->story->stageList['projected'] = '已立项'; +$lang->story->stageList['developing'] = '研发中'; +$lang->story->stageList['developed'] = '研发完毕'; +$lang->story->stageList['testing'] = '测试中'; +$lang->story->stageList['tested'] = '测试完毕'; +$lang->story->stageList['verified'] = '已验收'; +$lang->story->stageList['released'] = '已发布'; + +$lang->story->reasonList[''] = ''; +$lang->story->reasonList['done'] = '已完成'; +$lang->story->reasonList['subdivided'] = '已细分'; +$lang->story->reasonList['duplicate'] = '重复'; +$lang->story->reasonList['postponed'] = '延期'; +$lang->story->reasonList['willnotdo'] = '不做'; +$lang->story->reasonList['cancel'] = '已取消'; +$lang->story->reasonList['bydesign'] = '设计如此'; +//$lang->story->reasonList['isbug'] = '是个Bug'; + +$lang->story->reviewResultList[''] = ''; +$lang->story->reviewResultList['pass'] = '确认通过'; +$lang->story->reviewResultList['revert'] = '撤销变更'; +$lang->story->reviewResultList['clarify'] = '有待明确'; +$lang->story->reviewResultList['reject'] = '拒绝'; + +$lang->story->reviewList[0] = '否'; +$lang->story->reviewList[1] = '是'; + +$lang->story->sourceList[''] = ''; +$lang->story->sourceList['customer'] = '客户'; +$lang->story->sourceList['user'] = '用户'; +$lang->story->sourceList['po'] = '产品经理'; +$lang->story->sourceList['market'] = '市场'; +$lang->story->sourceList['service'] = '客服'; +$lang->story->sourceList['competitor'] = '竞争对手'; +$lang->story->sourceList['partner'] = '合作伙伴'; +$lang->story->sourceList['dev'] = '开发人员'; +$lang->story->sourceList['tester'] = '测试人员'; +$lang->story->sourceList['bug'] = 'Bug'; +$lang->story->sourceList['other'] = '其他'; + +$lang->story->priList[] = ''; +$lang->story->priList[3] = '3'; +$lang->story->priList[1] = '1'; +$lang->story->priList[2] = '2'; +$lang->story->priList[4] = '4'; + +$lang->story->legendBasicInfo = '基本信息'; +$lang->story->legendLifeTime = '需求的一生'; +$lang->story->legendRelated = '相关信息'; +$lang->story->legendMailto = '抄送给'; +$lang->story->legendAttatch = '附件'; +$lang->story->legendProjectAndTask = '项目任务'; +$lang->story->legendBugs = '相关Bug'; +$lang->story->legendFromBug = '来源Bug'; +$lang->story->legendCases = '相关用例'; +$lang->story->legendLinkStories = '相关需求'; +$lang->story->legendChildStories = '细分需求'; +$lang->story->legendSpec = '需求描述'; +$lang->story->legendVerify = '验收标准'; +$lang->story->legendHistory = '历史记录'; +$lang->story->legendVersion = '历史版本'; +$lang->story->legendMisc = '其他相关'; + +$lang->story->lblChange = '变更需求'; +$lang->story->lblReview = '评审需求'; +$lang->story->lblActivate = '激活需求'; +$lang->story->lblClose = '关闭需求'; + +$lang->story->affectedProjects = '影响的项目'; +$lang->story->affectedBugs = '影响的Bug'; +$lang->story->affectedCases = '影响的用例'; + +$lang->story->specTemplate = "建议参考的模板:作为一名<某种类型的用户>,我希望<达成某些目的>,这样可以<开发的价值>。"; +$lang->story->notes = '(注:如果“需求标题”为空,则表示不使用此行)'; +$lang->story->needNotReview = '不需要评审'; +$lang->story->confirmDelete = "您确认删除该需求吗?"; +$lang->story->errorFormat = '需求数据有误'; +$lang->story->errorEmptyTitle = '标题不能为空'; +$lang->story->mustChooseResult = '必须选择评审结果'; +$lang->story->mustChoosePreVersion = '必须选择回溯的版本'; +$lang->story->ajaxGetProjectStories = '接口:获取项目需求列表'; +$lang->story->ajaxGetProductStories = '接口:获取产品需求列表'; + +$lang->story->action->reviewed = array('main' => '$date, 由 $actor 记录评审结果,结果为 $extra。', 'extra' => $lang->story->reviewResultList); +$lang->story->action->closed = array('main' => '$date, 由 $actor 关闭,原因为 $extra。', 'extra' => $lang->story->reasonList); +$lang->story->action->linked2plan = array('main' => '$date, 由 $actor 关联到计划 $extra。'); +$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 从计划 $extra 移除。'); +$lang->story->action->linked2project = array('main' => '$date, 由 $actor 关联到项目 $extra。'); +$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 $actor 从项目 $extra 移除。'); + +/* 统计报表。*/ +$lang->story->report->common = '统计报表'; +$lang->story->report->select = '请选择报表类型'; +$lang->story->report->create = '生成报表'; +$lang->story->report->selectAll = '全选'; +$lang->story->report->selectReverse = '反选'; + +$lang->story->report->charts['storysPerProduct'] = '产品需求数量'; +$lang->story->report->charts['storysPerModule'] = '模块需求数量'; +$lang->story->report->charts['storysPerSource'] = '需求来源统计'; +$lang->story->report->charts['storysPerPlan'] = '计划进行统计'; +$lang->story->report->charts['storysPerStatus'] = '状态进行统计'; +$lang->story->report->charts['storysPerStage'] = '所处阶段进行统计'; +$lang->story->report->charts['storysPerPri'] = '优先级进行统计'; +$lang->story->report->charts['storysPerEstimate'] = '预计工时进行统计'; +$lang->story->report->charts['storysPerOpenedBy'] = '由谁创建来进行统计'; +$lang->story->report->charts['storysPerAssignedTo'] = '当前指派来进行统计'; +$lang->story->report->charts['storysPerClosedReason'] = '关闭原因来进行统计'; +$lang->story->report->charts['storysPerChange'] = '变更次数来进行统计'; + +$lang->story->report->options->swf = 'pie2d'; +$lang->story->report->options->width = 'auto'; +$lang->story->report->options->height = 300; +$lang->story->report->options->graph->baseFontSize = 12; +$lang->story->report->options->graph->showNames = 1; +$lang->story->report->options->graph->formatNumber = 1; +$lang->story->report->options->graph->decimalPrecision = 0; +$lang->story->report->options->graph->animation = 0; +$lang->story->report->options->graph->rotateNames = 0; +$lang->story->report->options->graph->yAxisName = 'COUNT'; +$lang->story->report->options->graph->pieRadius = 100; // 饼图直径。 +$lang->story->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 + +$lang->story->report->storysPerProduct->graph->xAxisName = '产品'; +$lang->story->report->storysPerModule->graph->xAxisName = '模块'; +$lang->story->report->storysPerSource->graph->xAxisName = '来源'; +$lang->story->report->storysPerPlan->graph->xAxisName = '产品计划'; +$lang->story->report->storysPerStatus->graph->xAxisName = '状态'; +$lang->story->report->storysPerStage->graph->xAxisName = '所处阶段'; +$lang->story->report->storysPerPri->graph->xAxisName = '优先级'; +$lang->story->report->storysPerOpenedBy->graph->xAxisName = '由谁创建'; +$lang->story->report->storysPerAssignedTo->graph->xAxisName = '当前指派'; +$lang->story->report->storysPerClosedReason->graph->xAxisName = '关闭原因'; +$lang->story->report->storysPerEstimate->graph->xAxisName = '预计时间'; +$lang->story->report->storysPerChange->graph->xAxisName = '变更次数'; diff --git a/module/story/lang/zh-tw.php b/module/story/lang/zh-tw.php index 460b6be7cc..0979625627 100644 --- a/module/story/lang/zh-tw.php +++ b/module/story/lang/zh-tw.php @@ -1,222 +1,222 @@ - - * @package story - * @version $Id: zh-tw.php 2572 2012-02-13 03:28:39Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->story->browse = "需求列表"; -$lang->story->create = "新增需求"; -$lang->story->createCase = "建用例"; -$lang->story->batchCreate = "批量添加"; -$lang->story->change = "變更"; -$lang->story->changed = '需求變更'; -$lang->story->review = '評審'; -$lang->story->edit = "編輯需求"; -$lang->story->close = '關閉'; -$lang->story->activate = '激活'; -$lang->story->delete = "刪除需求"; -$lang->story->view = "需求詳情"; -$lang->story->tasks = "相關任務"; -$lang->story->taskCount = '任務數'; -$lang->story->bugs = "Bug"; -$lang->story->linkStory = '關聯需求'; -$lang->story->export = "導出數據"; -$lang->story->reportChart = "統計報表"; - -$lang->story->common = '需求'; -$lang->story->id = '編號'; -$lang->story->product = '所屬產品'; -$lang->story->module = '所屬模組'; -$lang->story->source = '來源'; -$lang->story->release = '發佈計劃'; -$lang->story->bug = '相關bug'; -$lang->story->title = '需求名稱'; -$lang->story->spec = '需求描述'; -$lang->story->verify = '驗收標準'; -$lang->story->type = '需求類型 '; -$lang->story->pri = '優先順序'; -$lang->story->estimate = '預計工時'; -$lang->story->estimateAB = '預計'; -$lang->story->status = '當前狀態'; -$lang->story->stage = '所處階段'; -$lang->story->stageAB = '階段'; -$lang->story->mailto = '抄送給'; -$lang->story->openedBy = '由誰創建'; -$lang->story->openedDate = '創建日期'; -$lang->story->assignedTo = '指派給'; -$lang->story->assignedDate = '指派日期'; -$lang->story->lastEditedBy = '最後修改'; -$lang->story->lastEditedDate = '最後修改日期'; -$lang->story->lastEdited = '最後修改'; -$lang->story->closedBy = '由誰關閉'; -$lang->story->closedDate = '關閉日期'; -$lang->story->closedReason = '關閉原因'; -$lang->story->rejectedReason = '拒絶原因'; -$lang->story->reviewedBy = '由誰評審'; -$lang->story->reviewedDate = '評審時間'; -$lang->story->version = '版本號'; -$lang->story->project = '所屬項目'; -$lang->story->plan = '所屬計劃'; -$lang->story->planAB = '計劃'; -$lang->story->comment = '備註'; -$lang->story->linkStories = '相關需求'; -$lang->story->childStories = '細分需求'; -$lang->story->duplicateStory = '重複需求'; -$lang->story->reviewResult = '評審結果'; -$lang->story->preVersion = '之前版本'; -$lang->story->keywords = '關鍵詞'; - -$lang->story->same = '同上'; - -$lang->story->useList[0] = '不使用'; -$lang->story->useList[1] = '使用'; - -$lang->story->statusList[''] = ''; -$lang->story->statusList['draft'] = '草稿'; -$lang->story->statusList['active'] = '激活'; -$lang->story->statusList['closed'] = '已關閉'; -$lang->story->statusList['changed'] = '已變更'; - -$lang->story->stageList[''] = ''; -$lang->story->stageList['wait'] = '未開始'; -$lang->story->stageList['planned'] = '已計劃'; -$lang->story->stageList['projected'] = '已立項'; -$lang->story->stageList['developing'] = '研發中'; -$lang->story->stageList['developed'] = '研發完畢'; -$lang->story->stageList['testing'] = '測試中'; -$lang->story->stageList['tested'] = '測試完畢'; -$lang->story->stageList['verified'] = '已驗收'; -$lang->story->stageList['released'] = '已發佈'; - -$lang->story->reasonList[''] = ''; -$lang->story->reasonList['done'] = '已完成'; -$lang->story->reasonList['subdivided'] = '已細分'; -$lang->story->reasonList['duplicate'] = '重複'; -$lang->story->reasonList['postponed'] = '延期'; -$lang->story->reasonList['willnotdo'] = '不做'; -$lang->story->reasonList['cancel'] = '已取消'; -$lang->story->reasonList['bydesign'] = '設計如此'; -//$lang->story->reasonList['isbug'] = '是個Bug'; - -$lang->story->reviewResultList[''] = ''; -$lang->story->reviewResultList['pass'] = '確認通過'; -$lang->story->reviewResultList['revert'] = '撤銷變更'; -$lang->story->reviewResultList['clarify'] = '有待明確'; -$lang->story->reviewResultList['reject'] = '拒絶'; - -$lang->story->reviewList[0] = '否'; -$lang->story->reviewList[1] = '是'; - -$lang->story->sourceList[''] = ''; -$lang->story->sourceList['customer'] = '客戶'; -$lang->story->sourceList['user'] = '用戶'; -$lang->story->sourceList['po'] = '產品經理'; -$lang->story->sourceList['market'] = '市場'; -$lang->story->sourceList['service'] = '客服'; -$lang->story->sourceList['competitor'] = '競爭對手'; -$lang->story->sourceList['partner'] = '合作夥伴'; -$lang->story->sourceList['dev'] = '開發人員'; -$lang->story->sourceList['tester'] = '測試人員'; -$lang->story->sourceList['bug'] = 'Bug'; -$lang->story->sourceList['other'] = '其他'; - -$lang->story->priList[] = ''; -$lang->story->priList[3] = '3'; -$lang->story->priList[1] = '1'; -$lang->story->priList[2] = '2'; -$lang->story->priList[4] = '4'; - -$lang->story->legendBasicInfo = '基本信息'; -$lang->story->legendLifeTime = '需求的一生'; -$lang->story->legendRelated = '相關信息'; -$lang->story->legendMailto = '抄送給'; -$lang->story->legendAttatch = '附件'; -$lang->story->legendProjectAndTask = '項目任務'; -$lang->story->legendBugs = '相關Bug'; -$lang->story->legendFromBug = '來源Bug'; -$lang->story->legendCases = '相關用例'; -$lang->story->legendLinkStories = '相關需求'; -$lang->story->legendChildStories = '細分需求'; -$lang->story->legendSpec = '需求描述'; -$lang->story->legendVerify = '驗收標準'; -$lang->story->legendHistory = '歷史記錄'; -$lang->story->legendVersion = '歷史版本'; -$lang->story->legendMisc = '其他相關'; - -$lang->story->lblChange = '變更需求'; -$lang->story->lblReview = '評審需求'; -$lang->story->lblActivate = '激活需求'; -$lang->story->lblClose = '關閉需求'; - -$lang->story->affectedProjects = '影響的項目'; -$lang->story->affectedBugs = '影響的Bug'; -$lang->story->affectedCases = '影響的用例'; - -$lang->story->specTemplate = "建議參考的模板:作為一名<某種類型的用戶>,我希望<達成某些目的>,這樣可以<開發的價值>。"; -$lang->story->notes = '(註:如果“需求標題”為空,則表示不使用此行)'; -$lang->story->needNotReview = '不需要評審'; -$lang->story->confirmDelete = "您確認刪除該需求嗎?"; -$lang->story->errorFormat = '需求數據有誤'; -$lang->story->errorEmptyTitle = '標題不能為空'; -$lang->story->mustChooseResult = '必須選擇評審結果'; -$lang->story->mustChoosePreVersion = '必須選擇回溯的版本'; -$lang->story->ajaxGetProjectStories = '介面:獲取項目需求列表'; -$lang->story->ajaxGetProductStories = '介面:獲取產品需求列表'; - -$lang->story->action->reviewed = array('main' => '$date, 由 $actor 記錄評審結果,結果為 $extra。', 'extra' => $lang->story->reviewResultList); -$lang->story->action->closed = array('main' => '$date, 由 $actor 關閉,原因為 $extra。', 'extra' => $lang->story->reasonList); -$lang->story->action->linked2plan = array('main' => '$date, 由 $actor 關聯到計劃 $extra。'); -$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 從計劃 $extra 移除。'); -$lang->story->action->linked2project = array('main' => '$date, 由 $actor 關聯到項目 $extra。'); -$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 $actor 從項目 $extra 移除。'); - -/* 統計報表。*/ -$lang->story->report->common = '統計報表'; -$lang->story->report->select = '請選擇報表類型'; -$lang->story->report->create = '生成報表'; -$lang->story->report->selectAll = '全選'; -$lang->story->report->selectReverse = '反選'; - -$lang->story->report->charts['storysPerProduct'] = '產品需求數量'; -$lang->story->report->charts['storysPerModule'] = '模組需求數量'; -$lang->story->report->charts['storysPerSource'] = '需求來源統計'; -$lang->story->report->charts['storysPerPlan'] = '計划進行統計'; -$lang->story->report->charts['storysPerStatus'] = '狀態進行統計'; -$lang->story->report->charts['storysPerStage'] = '所處階段進行統計'; -$lang->story->report->charts['storysPerPri'] = '優先順序進行統計'; -$lang->story->report->charts['storysPerEstimate'] = '預計工時進行統計'; -$lang->story->report->charts['storysPerOpenedBy'] = '由誰創建來進行統計'; -$lang->story->report->charts['storysPerAssignedTo'] = '當前指派來進行統計'; -$lang->story->report->charts['storysPerClosedReason'] = '關閉原因來進行統計'; -$lang->story->report->charts['storysPerChange'] = '變更次數來進行統計'; - -$lang->story->report->options->swf = 'pie2d'; -$lang->story->report->options->width = 'auto'; -$lang->story->report->options->height = 300; -$lang->story->report->options->graph->baseFontSize = 12; -$lang->story->report->options->graph->showNames = 1; -$lang->story->report->options->graph->formatNumber = 1; -$lang->story->report->options->graph->decimalPrecision = 0; -$lang->story->report->options->graph->animation = 0; -$lang->story->report->options->graph->rotateNames = 0; -$lang->story->report->options->graph->yAxisName = 'COUNT'; -$lang->story->report->options->graph->pieRadius = 100; // 餅圖直徑。 -$lang->story->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 - -$lang->story->report->storysPerProduct->graph->xAxisName = '產品'; -$lang->story->report->storysPerModule->graph->xAxisName = '模組'; -$lang->story->report->storysPerSource->graph->xAxisName = '來源'; -$lang->story->report->storysPerPlan->graph->xAxisName = '產品計劃'; -$lang->story->report->storysPerStatus->graph->xAxisName = '狀態'; -$lang->story->report->storysPerStage->graph->xAxisName = '所處階段'; -$lang->story->report->storysPerPri->graph->xAxisName = '優先順序'; -$lang->story->report->storysPerOpenedBy->graph->xAxisName = '由誰創建'; -$lang->story->report->storysPerAssignedTo->graph->xAxisName = '當前指派'; -$lang->story->report->storysPerClosedReason->graph->xAxisName = '關閉原因'; -$lang->story->report->storysPerEstimate->graph->xAxisName = '預計時間'; -$lang->story->report->storysPerChange->graph->xAxisName = '變更次數'; + + * @package story + * @version $Id: zh-tw.php 2572 2012-02-13 03:28:39Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->story->browse = "需求列表"; +$lang->story->create = "新增需求"; +$lang->story->createCase = "建用例"; +$lang->story->batchCreate = "批量添加"; +$lang->story->change = "變更"; +$lang->story->changed = '需求變更'; +$lang->story->review = '評審'; +$lang->story->edit = "編輯需求"; +$lang->story->close = '關閉'; +$lang->story->activate = '激活'; +$lang->story->delete = "刪除需求"; +$lang->story->view = "需求詳情"; +$lang->story->tasks = "相關任務"; +$lang->story->taskCount = '任務數'; +$lang->story->bugs = "Bug"; +$lang->story->linkStory = '關聯需求'; +$lang->story->export = "導出數據"; +$lang->story->reportChart = "統計報表"; + +$lang->story->common = '需求'; +$lang->story->id = '編號'; +$lang->story->product = '所屬產品'; +$lang->story->module = '所屬模組'; +$lang->story->source = '來源'; +$lang->story->release = '發佈計劃'; +$lang->story->bug = '相關bug'; +$lang->story->title = '需求名稱'; +$lang->story->spec = '需求描述'; +$lang->story->verify = '驗收標準'; +$lang->story->type = '需求類型 '; +$lang->story->pri = '優先順序'; +$lang->story->estimate = '預計工時'; +$lang->story->estimateAB = '預計'; +$lang->story->status = '當前狀態'; +$lang->story->stage = '所處階段'; +$lang->story->stageAB = '階段'; +$lang->story->mailto = '抄送給'; +$lang->story->openedBy = '由誰創建'; +$lang->story->openedDate = '創建日期'; +$lang->story->assignedTo = '指派給'; +$lang->story->assignedDate = '指派日期'; +$lang->story->lastEditedBy = '最後修改'; +$lang->story->lastEditedDate = '最後修改日期'; +$lang->story->lastEdited = '最後修改'; +$lang->story->closedBy = '由誰關閉'; +$lang->story->closedDate = '關閉日期'; +$lang->story->closedReason = '關閉原因'; +$lang->story->rejectedReason = '拒絶原因'; +$lang->story->reviewedBy = '由誰評審'; +$lang->story->reviewedDate = '評審時間'; +$lang->story->version = '版本號'; +$lang->story->project = '所屬項目'; +$lang->story->plan = '所屬計劃'; +$lang->story->planAB = '計劃'; +$lang->story->comment = '備註'; +$lang->story->linkStories = '相關需求'; +$lang->story->childStories = '細分需求'; +$lang->story->duplicateStory = '重複需求'; +$lang->story->reviewResult = '評審結果'; +$lang->story->preVersion = '之前版本'; +$lang->story->keywords = '關鍵詞'; + +$lang->story->same = '同上'; + +$lang->story->useList[0] = '不使用'; +$lang->story->useList[1] = '使用'; + +$lang->story->statusList[''] = ''; +$lang->story->statusList['draft'] = '草稿'; +$lang->story->statusList['active'] = '激活'; +$lang->story->statusList['closed'] = '已關閉'; +$lang->story->statusList['changed'] = '已變更'; + +$lang->story->stageList[''] = ''; +$lang->story->stageList['wait'] = '未開始'; +$lang->story->stageList['planned'] = '已計劃'; +$lang->story->stageList['projected'] = '已立項'; +$lang->story->stageList['developing'] = '研發中'; +$lang->story->stageList['developed'] = '研發完畢'; +$lang->story->stageList['testing'] = '測試中'; +$lang->story->stageList['tested'] = '測試完畢'; +$lang->story->stageList['verified'] = '已驗收'; +$lang->story->stageList['released'] = '已發佈'; + +$lang->story->reasonList[''] = ''; +$lang->story->reasonList['done'] = '已完成'; +$lang->story->reasonList['subdivided'] = '已細分'; +$lang->story->reasonList['duplicate'] = '重複'; +$lang->story->reasonList['postponed'] = '延期'; +$lang->story->reasonList['willnotdo'] = '不做'; +$lang->story->reasonList['cancel'] = '已取消'; +$lang->story->reasonList['bydesign'] = '設計如此'; +//$lang->story->reasonList['isbug'] = '是個Bug'; + +$lang->story->reviewResultList[''] = ''; +$lang->story->reviewResultList['pass'] = '確認通過'; +$lang->story->reviewResultList['revert'] = '撤銷變更'; +$lang->story->reviewResultList['clarify'] = '有待明確'; +$lang->story->reviewResultList['reject'] = '拒絶'; + +$lang->story->reviewList[0] = '否'; +$lang->story->reviewList[1] = '是'; + +$lang->story->sourceList[''] = ''; +$lang->story->sourceList['customer'] = '客戶'; +$lang->story->sourceList['user'] = '用戶'; +$lang->story->sourceList['po'] = '產品經理'; +$lang->story->sourceList['market'] = '市場'; +$lang->story->sourceList['service'] = '客服'; +$lang->story->sourceList['competitor'] = '競爭對手'; +$lang->story->sourceList['partner'] = '合作夥伴'; +$lang->story->sourceList['dev'] = '開發人員'; +$lang->story->sourceList['tester'] = '測試人員'; +$lang->story->sourceList['bug'] = 'Bug'; +$lang->story->sourceList['other'] = '其他'; + +$lang->story->priList[] = ''; +$lang->story->priList[3] = '3'; +$lang->story->priList[1] = '1'; +$lang->story->priList[2] = '2'; +$lang->story->priList[4] = '4'; + +$lang->story->legendBasicInfo = '基本信息'; +$lang->story->legendLifeTime = '需求的一生'; +$lang->story->legendRelated = '相關信息'; +$lang->story->legendMailto = '抄送給'; +$lang->story->legendAttatch = '附件'; +$lang->story->legendProjectAndTask = '項目任務'; +$lang->story->legendBugs = '相關Bug'; +$lang->story->legendFromBug = '來源Bug'; +$lang->story->legendCases = '相關用例'; +$lang->story->legendLinkStories = '相關需求'; +$lang->story->legendChildStories = '細分需求'; +$lang->story->legendSpec = '需求描述'; +$lang->story->legendVerify = '驗收標準'; +$lang->story->legendHistory = '歷史記錄'; +$lang->story->legendVersion = '歷史版本'; +$lang->story->legendMisc = '其他相關'; + +$lang->story->lblChange = '變更需求'; +$lang->story->lblReview = '評審需求'; +$lang->story->lblActivate = '激活需求'; +$lang->story->lblClose = '關閉需求'; + +$lang->story->affectedProjects = '影響的項目'; +$lang->story->affectedBugs = '影響的Bug'; +$lang->story->affectedCases = '影響的用例'; + +$lang->story->specTemplate = "建議參考的模板:作為一名<某種類型的用戶>,我希望<達成某些目的>,這樣可以<開發的價值>。"; +$lang->story->notes = '(註:如果“需求標題”為空,則表示不使用此行)'; +$lang->story->needNotReview = '不需要評審'; +$lang->story->confirmDelete = "您確認刪除該需求嗎?"; +$lang->story->errorFormat = '需求數據有誤'; +$lang->story->errorEmptyTitle = '標題不能為空'; +$lang->story->mustChooseResult = '必須選擇評審結果'; +$lang->story->mustChoosePreVersion = '必須選擇回溯的版本'; +$lang->story->ajaxGetProjectStories = '介面:獲取項目需求列表'; +$lang->story->ajaxGetProductStories = '介面:獲取產品需求列表'; + +$lang->story->action->reviewed = array('main' => '$date, 由 $actor 記錄評審結果,結果為 $extra。', 'extra' => $lang->story->reviewResultList); +$lang->story->action->closed = array('main' => '$date, 由 $actor 關閉,原因為 $extra。', 'extra' => $lang->story->reasonList); +$lang->story->action->linked2plan = array('main' => '$date, 由 $actor 關聯到計劃 $extra。'); +$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 $actor 從計劃 $extra 移除。'); +$lang->story->action->linked2project = array('main' => '$date, 由 $actor 關聯到項目 $extra。'); +$lang->story->action->unlinkedfromproject = array('main' => '$date, 由 $actor 從項目 $extra 移除。'); + +/* 統計報表。*/ +$lang->story->report->common = '統計報表'; +$lang->story->report->select = '請選擇報表類型'; +$lang->story->report->create = '生成報表'; +$lang->story->report->selectAll = '全選'; +$lang->story->report->selectReverse = '反選'; + +$lang->story->report->charts['storysPerProduct'] = '產品需求數量'; +$lang->story->report->charts['storysPerModule'] = '模組需求數量'; +$lang->story->report->charts['storysPerSource'] = '需求來源統計'; +$lang->story->report->charts['storysPerPlan'] = '計划進行統計'; +$lang->story->report->charts['storysPerStatus'] = '狀態進行統計'; +$lang->story->report->charts['storysPerStage'] = '所處階段進行統計'; +$lang->story->report->charts['storysPerPri'] = '優先順序進行統計'; +$lang->story->report->charts['storysPerEstimate'] = '預計工時進行統計'; +$lang->story->report->charts['storysPerOpenedBy'] = '由誰創建來進行統計'; +$lang->story->report->charts['storysPerAssignedTo'] = '當前指派來進行統計'; +$lang->story->report->charts['storysPerClosedReason'] = '關閉原因來進行統計'; +$lang->story->report->charts['storysPerChange'] = '變更次數來進行統計'; + +$lang->story->report->options->swf = 'pie2d'; +$lang->story->report->options->width = 'auto'; +$lang->story->report->options->height = 300; +$lang->story->report->options->graph->baseFontSize = 12; +$lang->story->report->options->graph->showNames = 1; +$lang->story->report->options->graph->formatNumber = 1; +$lang->story->report->options->graph->decimalPrecision = 0; +$lang->story->report->options->graph->animation = 0; +$lang->story->report->options->graph->rotateNames = 0; +$lang->story->report->options->graph->yAxisName = 'COUNT'; +$lang->story->report->options->graph->pieRadius = 100; // 餅圖直徑。 +$lang->story->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 + +$lang->story->report->storysPerProduct->graph->xAxisName = '產品'; +$lang->story->report->storysPerModule->graph->xAxisName = '模組'; +$lang->story->report->storysPerSource->graph->xAxisName = '來源'; +$lang->story->report->storysPerPlan->graph->xAxisName = '產品計劃'; +$lang->story->report->storysPerStatus->graph->xAxisName = '狀態'; +$lang->story->report->storysPerStage->graph->xAxisName = '所處階段'; +$lang->story->report->storysPerPri->graph->xAxisName = '優先順序'; +$lang->story->report->storysPerOpenedBy->graph->xAxisName = '由誰創建'; +$lang->story->report->storysPerAssignedTo->graph->xAxisName = '當前指派'; +$lang->story->report->storysPerClosedReason->graph->xAxisName = '關閉原因'; +$lang->story->report->storysPerEstimate->graph->xAxisName = '預計時間'; +$lang->story->report->storysPerChange->graph->xAxisName = '變更次數'; diff --git a/module/story/model.php b/module/story/model.php index f0cc5e89c2..e5cb6e1102 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -1,1211 +1,1211 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->findById((int)$storyID)->from(TABLE_STORY)->fetch(); - if(!$story) return false; - if(substr($story->closedDate, 0, 4) == '0000') $story->closedDate = ''; - if($version == 0) $version = $story->version; - $spec = $this->dao->select('title,spec,verify')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWhere('version')->eq($version)->fetch(); - $story->title = isset($spec->title) ? $spec->title : ''; - $story->spec = isset($spec->spec) ? $this->loadModel('file')->setImgSize($spec->spec) : ''; - $story->verify = isset($spec->verify) ? $spec->verify : ''; - $story->projects = $this->dao->select('t1.project, t2.name, t2.status') - ->from(TABLE_PROJECTSTORY)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2') - ->on('t1.project = t2.id') - ->where('t1.story')->eq($storyID) - ->orderBy('t1.project DESC') - ->fetchAll('project'); - $story->tasks = $this->dao->select('id, name, assignedTo, project, status, consumed, `left`')->from(TABLE_TASK)->where('story')->eq($storyID)->orderBy('id DESC')->fetchGroup('project'); - //$story->bugCount = $this->dao->select('COUNT(*)')->alias('count')->from(TABLE_BUG)->where('story')->eq($storyID)->fetch('count'); - //$story->caseCount = $this->dao->select('COUNT(*)')->alias('count')->from(TABLE_CASE)->where('story')->eq($storyID)->fetch('count'); - if($story->toBug) $story->toBugTitle = $this->dao->findById($story->toBug)->from(TABLE_BUG)->fetch('title'); - if($story->plan) $story->planTitle = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title'); - $extraStories = array(); - if($story->duplicateStory) $extraStories = array($story->duplicateStory); - if($story->linkStories) $extraStories = explode(',', $story->linkStories); - if($story->childStories) $extraStories = array_merge($extraStories, explode(',', $story->childStories)); - $extraStories = array_unique($extraStories); - if(!empty($extraStories)) $story->extraStories = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($extraStories)->fetchPairs(); - return $story; - } - - /** - * Get affected things. - * - * @param object $story - * @access public - * @return object - */ - public function getAffectedScope($story) - { - /* Remove closed projects. */ - if($story->projects) - { - foreach($story->projects as $projectID => $project) - { - if($project->status != 'doing') unset($story->projects[$projectID]); - } - } - - /* Get team members. */ - if($story->projects) - { - $story->teams = $this->dao->select('account, project') - ->from(TABLE_TEAM) - ->where('project')->in(array_keys($story->projects)) - ->fetchGroup('project'); - } - - /* Get affected bugs. */ - $story->bugs = $this->dao->findByStory($story->id)->from(TABLE_BUG) - ->andWhere('status')->ne('closed') - ->andWhere('deleted')->eq(0) - ->orderBy('id desc')->fetchAll(); - - /* Get affected cases. */ - $story->cases = $this->dao->findByStory($story->id)->from(TABLE_CASE)->andWhere('deleted')->eq(0)->fetchAll(); - - return $story; - } - - /** - * Create a story. - * - * @access public - * @return int|bool the id of the created story or false when error. - */ - public function create($projectID = 0, $bugID = 0) - { - $now = helper::now(); - $story = fixer::input('post') - ->cleanInt('product,module,pri,plan') - ->cleanFloat('estimate') - ->stripTags('title') - ->callFunc('title', 'trim') - ->setDefault('plan', 0) - ->add('openedBy', $this->app->user->account) - ->add('openedDate', $now) - ->add('assignedDate', 0) - ->add('version', 1) - ->add('status', 'draft') - ->setIF($this->post->assignedTo != '', 'assignedDate', $now) - ->setIF($this->post->needNotReview, 'status', 'active') - ->setIF($this->post->plan > 0, 'stage', 'planned') - ->setIF($projectID > 0, 'stage', 'projected') - ->setIF($bugID > 0, 'fromBug', $bugID) - ->remove('files,labels,spec,verify,needNotReview') - ->get(); - - $this->dao->insert(TABLE_STORY)->data($story)->autoCheck()->batchCheck($this->config->story->create->requiredFields, 'notempty')->exec(); - if(!dao::isError()) - { - $storyID = $this->dao->lastInsertID(); - $this->loadModel('file')->saveUpload('story', $storyID, $extra = 1); - - $data->story = $storyID; - $data->version = 1; - $data->title = $story->title; - $data->spec = $this->post->spec; - $data->verify = $this->post->verify; - $this->dao->insert(TABLE_STORYSPEC)->data($data)->exec(); - - if($projectID != 0) - { - $this->dao->insert(TABLE_PROJECTSTORY) - ->set('company')->eq(1) - ->set('project')->eq($projectID) - ->set('product')->eq($this->post->product) - ->set('story')->eq($storyID) - ->set('version')->eq(1) - ->exec(); - } - - if($bugID > 0) - { - $bug->toStory = $storyID; - $bug->status = 'closed'; - $bug->resolution = 'tostory'; - $bug->resolvedBy = $this->app->user->account; - $bug->resolvedDate = $now; - $bug->closedBy = $this->app->user->account; - $bug->closedDate = $now; - $bug->assignedTo = 'closed'; - $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec(); - - $this->loadModel('action')->create('bug', $bugID, 'ToStory', '', $storyID); - $this->action->create('bug', $bugID, 'Closed'); - - /* add files to story from bug. */ - $files = $this->dao->select('*')->from(TABLE_FILE) - ->where('objectType')->eq('bug') - ->andWhere('objectID')->eq($bugID) - ->fetchAll(); - if(!empty($files)) - { - foreach($files as $file) - { - $file->objectType = 'story'; - $file->objectID = $storyID; - unset($file->id); - $this->dao->insert(TABLE_FILE)->data($file)->exec(); - } - } - } - return $storyID; - } - return false; - } - - /** - * Create a batch stories. - * - * @access public - * @return int|bool the id of the created story or false when error. - */ - public function batchCreate($productID = 0) - { - $now = helper::now(); - $stories = fixer::input('post')->get(); - for($i = 0; $i < $this->config->story->batchCreate; $i++) - { - if($stories->title[$i] != '') - { - $data[$i]->module = $stories->module[$i] != 'same' ? $stories->module[$i] : ($i == 0 ? 0 : $data[$i-1]->module); - $data[$i]->plan = $stories->plan[$i] == 'same' ? ($i != 0 ? $data[$i-1]->plan : 0) : ($stories->plan[$i] != '' ? $stories->plan[$i] : 0); - $data[$i]->title = $stories->title[$i]; - $data[$i]->pri = $stories->pri[$i] != '' ? $stories->pri[$i] : 0; - $data[$i]->estimate = $stories->estimate[$i] != '' ? $stories->estimate[$i] : 0; - $data[$i]->status = $stories->needReview[$i] == 0 ? 'active' : 'draft'; - $data[$i]->product = $productID; - $data[$i]->openedBy = $this->app->user->account; - $data[$i]->openedDate = $now; - $data[$i]->version = 1; - - $this->dao->insert(TABLE_STORY) - ->data($data[$i]) - ->autoCheck() - ->batchCheck($this->config->story->create->requiredFields, 'notempty') - ->exec(); - if(dao::isError()) - { - echo js::error(dao::getError()); - die(js::reload('parent')); - } - - $storyID = $this->dao->lastInsertID(); - - $specData[$i]->story = $storyID; - $specData[$i]->version = 1; - $specData[$i]->title = $stories->title[$i]; - if($stories->spec[$i] != '') $specData[$i]->spec = $stories->spec[$i]; - $this->dao->insert(TABLE_STORYSPEC)->data($specData[$i])->exec(); - - $this->loadModel('action'); - $actionID = $this->action->create('story', $storyID, 'Opened', ''); - $mails[$i]->storyID = $storyID; - $mails[$i]->actionID = $actionID; - } - else - { - unset($stories->use[$i]); - unset($stories->module[$i]); - unset($stories->plan[$i]); - unset($stories->title[$i]); - unset($stories->spec[$i]); - unset($stories->pri[$i]); - unset($stories->estimate[$i]); - unset($stories->needReview[$i]); - } - } - return $mails; - } - - /** - * Change a story. - * - * @param int $storyID - * @access public - * @return array the change of the story. - */ - public function change($storyID) - { - $now = helper::now(); - $oldStory = $this->getById($storyID); - $specChanged = false; - if($this->post->spec != $oldStory->spec or $this->post->verify != $oldStory->verify or $this->post->title != $oldStory->title or $this->loadModel('file')->getCount()) $specChanged = true; - - $story = fixer::input('post') - ->stripTags('title') - ->callFunc('title', 'trim') - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->setIF($this->post->assignedTo != $oldStory->assignedTo, 'assignedDate', $now) - ->setIF($specChanged, 'version', $oldStory->version + 1) - ->setIF($specChanged and $oldStory->status == 'active' and $this->post->needNotReview == false, 'status', 'changed') - ->setIF($specChanged and $oldStory->status == 'draft' and $this->post->needNotReview, 'status', 'active') - ->setIF($specChanged, 'reviewedBy', '') - ->setIF($specChanged, 'closedBy', '') - ->setIF($specChanged, 'closedReason', '') - ->setIF($specChanged and $oldStory->reviewedBy, 'reviewedDate', '0000-00-00') - ->setIF($specChanged and $oldStory->closedBy, 'closedDate', '0000-00-00') - ->remove('files,labels,spec,verify,comment,needNotReview') - ->get(); - $this->dao->update(TABLE_STORY) - ->data($story) - ->autoCheck() - ->batchCheck($this->config->story->change->requiredFields, 'notempty') - ->where('id')->eq((int)$storyID)->exec(); - if(!dao::isError()) - { - if($specChanged) - { - $data->story = $storyID; - $data->version = $oldStory->version + 1; - $data->title = $story->title; - $data->spec = $this->post->spec; - $data->verify = $this->post->verify; - $this->dao->insert(TABLE_STORYSPEC)->data($data)->exec(); - $story->spec = $this->post->spec; - $story->verify = $this->post->verify; - } - else - { - unset($oldStory->spec); - } - return common::createChanges($oldStory, $story); - } - } - - /** - * Update a story. - * - * @param int $storyID - * @access public - * @return array the changes of the story. - */ - public function update($storyID) - { - $now = helper::now(); - $oldStory = $this->getById($storyID); - - $story = fixer::input('post') - ->cleanInt('product,module,pri,plan') - ->stripTags('title') - ->add('assignedDate', $oldStory->assignedDate) - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->setDefault('plan', 0) - ->setDefault('status', $oldStory->status) - ->setIF($this->post->assignedTo != $oldStory->assignedTo, 'assignedDate', $now) - ->setIF($this->post->closedBy != false and $oldStory->closedDate == '', 'closedDate', $now) - ->setIF($this->post->closedReason != false and $oldStory->closedDate == '', 'closedDate', $now) - ->setIF($this->post->closedBy != false or $this->post->closedReason != false, 'status', 'closed') - ->setIF($this->post->closedReason != false and $this->post->closedBy == false, 'closedBy', $this->app->user->account) - ->remove('files,labels,comment') - ->get(); - - $this->dao->update(TABLE_STORY) - ->data($story) - ->autoCheck() - ->batchCheck($this->config->story->edit->requiredFields, 'notempty') - ->checkIF(isset($story->closedBy), 'closedReason', 'notempty') - ->checkIF(isset($story->closedReason) and $story->closedReason == 'done', 'stage', 'notempty') - ->checkIF(isset($story->closedReason) and $story->closedReason == 'duplicate', 'duplicateStory', 'notempty') - ->checkIF(isset($story->closedReason) and $story->closedReason == 'subdivided', 'childStories', 'notempty') - ->where('id')->eq((int)$storyID)->exec(); - - if(!dao::isError()) return common::createChanges($oldStory, $story); - } - - /** - * Review a story. - * - * @param int $storyID - * @access public - * @return bool - */ - public function review($storyID) - { - if($this->post->result == false) die(js::alert($this->lang->story->mustChooseResult)); - if($this->post->result == 'revert' and $this->post->preVersion == false) die(js::alert($this->lang->story->mustChoosePreVersion)); - - $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); - $now = helper::now(); - $date = helper::today(); - $story = fixer::input('post') - ->remove('result,preVersion,comment') - ->setDefault('reviewedDate', $date) - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->setIF($this->post->result == 'pass' and $oldStory->status == 'draft', 'status', 'active') - ->setIF($this->post->result == 'pass' and $oldStory->status == 'changed', 'status', 'active') - ->setIF($this->post->result == 'reject', 'closedBy', $this->app->user->account) - ->setIF($this->post->result == 'reject', 'closedDate', $now) - ->setIF($this->post->result == 'reject', 'assignedTo', 'closed') - ->setIF($this->post->result == 'reject', 'status', 'closed') - ->setIF($this->post->result == 'revert', 'version', $this->post->preVersion) - ->setIF($this->post->result == 'revert', 'status', 'active') - ->setIF($this->post->closedReason == 'done', 'stage', 'released') - ->removeIF($this->post->result != 'reject', 'closedReason, duplicateStory, childStories') - ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'duplicate', 'duplicateStory') - ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'subdivided', 'childStories') - ->get(); - $this->dao->update(TABLE_STORY)->data($story) - ->autoCheck() - ->batchCheck($this->config->story->review->requiredFields, 'notempty') - ->checkIF($this->post->result == 'reject', 'closedReason', 'notempty') - ->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'duplicate', 'duplicateStory', 'notempty') - ->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'subdivided', 'childStories', 'notempty') - ->where('id')->eq($storyID)->exec(); - if($this->post->result == 'revert') - { - $preTitle = $this->dao->select('title')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWHere('version')->eq($this->post->preVersion)->fetch('title'); - $this->dao->update(TABLE_STORY)->set('title')->eq($preTitle)->where('id')->eq($storyID)->exec(); - $this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWHere('version')->eq($oldStory->version)->exec(); - $this->dao->delete()->from(TABLE_FILE)->where('objectType')->eq('story')->andWhere('objectID')->eq($storyID)->andWhere('extra')->eq($oldStory->version)->exec(); - } - $this->setStage($storyID); - return true; - } - - /** - * Close a story. - * - * @param int $storyID - * @access public - * @return bool - */ - public function close($storyID) - { - $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); - $now = helper::now(); - $story = fixer::input('post') - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->add('closedDate', $now) - ->add('closedBy', $this->app->user->account) - ->add('assignedTo', 'closed') - ->add('assignedDate', $now) - ->add('status', 'closed') - ->removeIF($this->post->closedReason != 'duplicate', 'duplicateStory') - ->removeIF($this->post->closedReason != 'subdivided', 'childStories') - ->setIF($this->post->closedReason == 'done', 'stage', 'released') - ->setIF($this->post->closedReason != 'done', 'plan', 0) - ->remove('comment') - ->get(); - $this->dao->update(TABLE_STORY)->data($story) - ->autoCheck() - ->batchCheck($this->config->story->close->requiredFields, 'notempty') - ->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty') - ->checkIF($story->closedReason == 'subdivided', 'childStories', 'notempty') - ->where('id')->eq($storyID)->exec(); - return true; - } - - /** - * Activate a story. - * - * @param int $storyID - * @access public - * @return bool - */ - public function activate($storyID) - { - $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); - $now = helper::now(); - $story = fixer::input('post') - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->add('assignedDate', $now) - ->add('status', 'active') - ->add('closedBy', '') - ->add('closedReason', '') - ->add('closedDate', '0000-00-00') - ->add('reviewedBy', '') - ->add('reviewedDate', '0000-00-00') - ->remove('comment') - ->get(); - $this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq($storyID)->exec(); - return true; - } - - /** - * Set stage of a story. - * - * @param int $storyID - * @param string $customStage - * @access public - * @return bool - */ - public function setStage($storyID, $customStage = '') - { - /* Custom stage defined, use it. */ - if($customStage) - { - $this->dao->update(TABLE_STORY)->set('stage')->eq($customStage)->where('id')->eq((int)$storyID)->exec(); - return true; - } - - /* Get projects which status is doing. */ - $projects = $this->dao->select('project') - ->from(TABLE_PROJECTSTORY)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t1.story')->eq((int)$storyID) - ->andWhere('t2.status')->ne('done') - ->andWhere('t2.deleted')->eq(0) - ->fetchPairs(); - - /* If no projects, in plan, stage is planned. No plan, wait. */ - if(!$projects) - { - $this->dao->update(TABLE_STORY)->set('stage')->eq('planned')->where('id')->eq((int)$storyID)->andWhere('plan')->gt(0)->exec(); - $this->dao->update(TABLE_STORY)->set('stage')->eq('wait')->where('id')->eq((int)$storyID)->andWhere('plan')->eq(0)->andWhere('status')->eq('active')->exec(); - return true; - } - - /* Search related tasks. */ - $tasks = $this->dao->select('type,status')->from(TABLE_TASK) - ->where('project')->in($projects) - ->andWhere('story')->eq($storyID) - ->andWhere('status')->ne('cancel') - ->andWhere('status')->ne('closed') - ->andWhere('deleted')->eq(0) - ->fetchGroup('type'); - - /* No tasks, then the stage is projected. */ - if(!$tasks) - { - $this->dao->update(TABLE_STORY)->set('stage')->eq('projected')->where('id')->eq((int)$storyID)->exec(); - return true; - } - - /* If have test task, the stage is tested, testing or developing. */ - if(isset($tasks['test'])) - { - $stage = 'tested'; - foreach($tasks['test'] as $task) - { - if($task->status != 'done') - { - $stage = 'testing'; - break; - } - } - if($stage != 'testing') - { - unset($tasks['test']); - foreach($tasks as $type => $typeTasks) - { - foreach($typeTasks as $task) - { - if($task->status != 'done') - { - $stage = 'developing'; - break; - } - } - } - } - } - /* No test taske, stage is done or developing. */ - else - { - $stage = 'developed'; - foreach($tasks as $type => $typeTasks) - { - foreach($typeTasks as $task) - { - if($task->status != 'done') - { - $stage = 'developing'; - break; - } - } - } - } - $this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq((int)$storyID)->exec(); - return; - } - - /** - * Get stories list of a product. - * - * @param int $productID - * @param array|string $moduleIds - * @param string $status - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getProductStories($productID = 0, $moduleIds = 0, $status = 'all', $orderBy = 'id_desc', $pager = null) - { - $stories = $this->dao->select('t1.*, t2.title as planTitle') - ->from(TABLE_STORY)->alias('t1') - ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') - ->where('t1.product')->in($productID) - ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi() - ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() - ->andWhere('t1.deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - - $this->saveReportQuery($this->dao->get()); - - return $stories; - } - - /** - * Get stories pairs of a product. - * - * @param int $productID - * @param array|string $moduleIds - * @param string $status - * @param string $order - * @access public - * @return array - */ - public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc') - { - $stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product') - ->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') - ->where('1=1') - ->beginIF($productID)->andWhere('t1.product')->in($productID)->fi() - ->beginIF($moduleIds)->andWhere('t1.module')->in($moduleIds)->fi() - ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() - ->andWhere('t1.deleted')->eq(0) - ->orderBy($order) - ->fetchAll(); - if(!$stories) return array(); - return $this->formatStories($stories); - } - - /** - * Get stories by assignedTo. - * - * @param int $productID - * @param string $account - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByAssignedTo($productID, $account, $orderBy, $pager) - { - return $this->getByField($productID, 'assignedTo', $account, $orderBy, $pager); - } - - /** - * Get stories by openedBy. - * - * @param int $productID - * @param string $account - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByOpenedBy($productID, $account, $orderBy, $pager) - { - return $this->getByField($productID, 'openedBy', $account, $orderBy, $pager); - } - - /** - * Get stories by reviewedBy. - * - * @param int $productID - * @param string $account - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getByReviewedBy($productID, $account, $orderBy, $pager) - { - return $this->getByField($productID, 'reviewedBy', $account, $orderBy, $pager, 'include'); - } - - /** - * Get stories by closedBy. - * - * @param int $productID - * @param string $account - * @param string $orderBy - * @param object $pager - * @return array - */ - public function getByClosedBy($productID, $account, $orderBy, $pager) - { - return $this->getByField($productID, 'closedBy', $account, $orderBy, $pager); - } - - /** - * Get stories by status. - * - * @param int $productID - * @param string $orderBy - * @param object $pager - * @param string $status - * @access public - * @return array - */ - public function getByStatus($productID, $status, $orderBy, $pager) - { - return $this->getByField($productID, 'status', $status, $orderBy, $pager); - } - - /** - * Get stories by a field. - * - * @param int $productID - * @param string $fieldName - * @param mixed $fieldValue - * @param string $orderBy - * @param object $pager - * @param string $operator equal|include - * @access public - * @return array - */ - public function getByField($productID, $fieldName, $fieldValue, $orderBy, $pager, $operator = 'equal') - { - $stories = $this->dao->select('t1.*, t2.title as planTitle') - ->from(TABLE_STORY)->alias('t1') - ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') - ->where('t1.product')->in($productID) - ->andWhere('t1.deleted')->eq(0) - ->beginIF($operator == 'equal')->andWhere($fieldName)->eq($fieldValue)->fi() - ->beginIF($operator == 'include')->andWhere($fieldName)->like("%$fieldValue%")->fi() - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - $this->saveReportQuery($this->dao->get()); - - return $stories; - } - - /** - * Get stories through search. - * - * @access public - * @param int $productID - * @param int $queryID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getBySearch($productID, $queryID, $orderBy, $pager) - { - $products = $this->loadModel('product')->getPairs(); - $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : ''; - - /* Get the sql and form status from the query. */ - if($query) - { - $this->session->set('storyQuery', $query->sql); - $this->session->set('storyForm', $query->form); - } - if($this->session->storyQuery == false) $this->session->set('storyQuery', ' 1 = 1'); - - $allProduct = "`product` = 'all'"; - $storyQuery = $this->session->storyQuery; - $queryProductID = $productID; - if(strpos($this->session->storyQuery, $allProduct) !== false) - { - $storyQuery = str_replace($allProduct, '1', $this->session->storyQuery); - $queryProductID = 'all'; - } - $storyQuery = $storyQuery . 'AND `product`' . helper::dbIN(array_keys($products)); - - return $this->getBySQL($queryProductID, $storyQuery, $orderBy, $pager); - } - - /** - * Get stories by a sql. - * - * @param int $productID - * @param string $sql - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getBySQL($productID, $sql, $orderBy, $pager = null) - { - $tmpStories = $this->dao->select('*')->from(TABLE_STORY)->where($sql) - ->beginIF($productID != 'all')->andWhere('product')->eq((int)$productID)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll('id'); - $this->saveReportQuery($this->dao->get()); - - if(!$tmpStories) return array(); - - /* Get plans. */ - $plans = array(); - foreach($tmpStories as $story) $plans[$story->plan] = $story->plan; - $plans = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)->where('id')->in(array_keys($plans))->fetchPairs(); - - /* Process plans. */ - $stories = array(); - foreach($tmpStories as $story) - { - $story->planTitle = isset($plans[$story->plan]) ? $plans[$story->plan] : ''; - $stories[] = $story; - } - return $stories; - } - - /** - * Save one executed query as report query, thus when create report chart to make use the condition is the same. - * - * @param string $sql - * @access public - * @return void - */ - public function saveReportQuery($sql) - { - $sql = explode('WHERE', $sql); - $sql = explode('ORDER', $sql[1]); - $sql = str_replace('t1.', '', $sql[0]); - $this->session->set('storyReport', $sql); - } - - /** - * Get stories list of a project. - * - * @param int $projectID - * @param string $orderBy - * @access public - * @return array - */ - public function getProjectStories($projectID = 0, $orderBy = 'pri_asc,id_desc') - { - return $this->dao->select('t1.*, t2.*')->from(TABLE_PROJECTSTORY)->alias('t1') - ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t2.deleted')->eq(0) - ->orderBy($orderBy) - ->fetchAll('id'); - } - - /** - * Get stories pairs of a project. - * - * @param int $projectID - * @param int $productID - * @access public - * @return array - */ - public function getProjectStoryPairs($projectID = 0, $productID = 0) - { - $stories = $this->dao->select('t2.id, t2.title, t2.module, t2.pri, t2.estimate, t3.name AS product') - ->from(TABLE_PROJECTSTORY)->alias('t1') - ->leftJoin(TABLE_STORY)->alias('t2') - ->on('t1.story = t2.id') - ->leftJoin(TABLE_PRODUCT)->alias('t3') - ->on('t1.product = t3.id') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t2.deleted')->eq(0) - ->beginIF($productID)->andWhere('t1.product')->eq((int)$productID)->fi() - ->fetchAll(); - if(!$stories) return array(); - return $this->formatStories($stories); - } - - /** - * Get stories list of a plan. - * - * @param int $planID - * @param string $status - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getPlanStories($planID, $status = 'all', $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('*')->from(TABLE_STORY) - ->where('plan')->eq((int)$planID) - ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll('id'); - } - - /** - * Get stories pairs of a plan. - * - * @param int $planID - * @param string $status - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getPlanStoryPairs($planID, $status = 'all', $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('*')->from(TABLE_STORY) - ->where('plan')->eq($planID) - ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() - ->andWhere('deleted')->eq(0) - ->fetchAll(); - } - - /** - * Get stories of a user. - * - * @param string $account - * @param string $type the query type - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getUserStories($account, $type = 'assignedto', $orderBy = 'id_desc', $pager = null) - { - $type = strtolower($type); - return $this->dao->select('t1.*, t2.title as planTitle, t3.name as productTitle') - ->from(TABLE_STORY)->alias('t1') - ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') - ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') - ->where('t1.deleted')->eq(0) - ->beginIF($type == 'assignedto')->andWhere('assignedTo')->eq($this->app->user->account)->fi() - ->beginIF($type == 'openedby')->andWhere('openedby')->eq($this->app->user->account)->fi() - ->beginIF($type == 'reviewedby')->andWhere('reviewedby')->like('%' . $this->app->user->account . '%')->fi() - ->beginIF($type == 'closedby')->andWhere('closedby')->eq($this->app->user->account)->fi() - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get doing projects' members of a story. - * - * @param int $storyID - * @access public - * @return array - */ - public function getProjectMembers($storyID) - { - $projects = $this->dao->select('project') - ->from(TABLE_PROJECTSTORY)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t1.story')->eq((int)$storyID) - ->andWhere('t2.status')->eq('doing') - ->andWhere('t2.deleted')->eq(0) - ->fetchPairs(); - if($projects) return($this->dao->select('account')->from(TABLE_TEAM)->where('project')->in($projects)->fetchPairs('account')); - } - - /** - * Get version of a story. - * - * @param int $storyID - * @access public - * @return int - */ - public function getVersion($storyID) - { - return $this->dao->select('version')->from(TABLE_STORY)->where('id')->eq((int)$storyID)->fetch('version'); - } - - /** - * Get versions of some stories. - * - * @param array|string story id list - * @access public - * @return array - */ - public function getVersions($storyID) - { - return $this->dao->select('id, version')->from(TABLE_STORY)->where('id')->in($storyID)->fetchPairs(); - } - - /** - * Format stories - * - * @param array $stories - * @access public - * @return void - */ - public function formatStories($stories) - { - /* Get module names of stories. */ - /*$modules = array(); - foreach($stories as $story) $modules[] = $story->module; - $moduleNames = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($modules)->fetchPairs();*/ - - /* Format these stories. */ - $storyPairs = array('' => ''); - foreach($stories as $story) $storyPairs[$story->id] = $story->id . ':' . $story->title . "({$this->lang->story->pri}:$story->pri, {$this->lang->story->estimate}: $story->estimate)"; - return $storyPairs; - } - - /** - * Extract accounts from some stories. - * - * @param array $stories - * @access public - * @return array - */ - public function extractAccountsFromList($stories) - { - $accounts = array(); - foreach($stories as $story) - { - if(!empty($story->openedBy)) $accounts[] = $story->openedBy; - if(!empty($story->assignedTo)) $accounts[] = $story->assignedTo; - if(!empty($story->closedBy)) $accounts[] = $story->closedBy; - if(!empty($story->lastEditedBy)) $accounts[] = $story->lastEditedBy; - } - return array_unique($accounts); - } - - /** - * Extract accounts from a story. - * - * @param object $story - * @access public - * @return array - */ - public function extractAccountsFromSingle($story) - { - $accounts = array(); - if(!empty($story->openedBy)) $accounts[] = $story->openedBy; - if(!empty($story->assignedTo)) $accounts[] = $story->assignedTo; - if(!empty($story->closedBy)) $accounts[] = $story->closedBy; - if(!empty($story->lastEditedBy)) $accounts[] = $story->lastEditedBy; - return array_unique($accounts); - } - - /** - * Merge the default chart settings and the settings of current chart. - * - * @param string $chartType - * @access public - * @return void - */ - public function mergeChartOption($chartType) - { - $chartOption = $this->lang->story->report->$chartType; - $commonOption = $this->lang->story->report->options; - - $chartOption->graph->caption = $this->lang->story->report->charts[$chartType]; - if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; - if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; - if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; - - foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; - } - - /** - * Get report data of storys per product - * - * @access public - * @return array - */ - public function getDataOfStorysPerProduct() - { - $datas = $this->dao->select('product as name, count(product) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('product')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $products = $this->loadModel('product')->getPairs(); - foreach($datas as $productID => $data) $data->name = isset($products[$productID]) ? $products[$productID] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per module - * - * @access public - * @return array - */ - public function getDataOfStorysPerModule() - { - $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('module')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs(); - foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/'; - return $datas; - } - - /** - * Get report data of storys per source - * - * @access public - * @return array - */ - public function getDataOfStorysPerSource() - { - $datas = $this->dao->select('source as name, count(source) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('source')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $this->lang->story->sourceList[''] = $this->lang->report->undefined; - foreach($datas as $key => $data) $data->name = isset($this->lang->story->sourceList[$key]) ? $this->lang->story->sourceList[$key] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per plan - * - * @access public - * @return array - */ - public function getDataOfStorysPerPlan() - { - $datas = $this->dao->select('plan as name, count(plan) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('plan')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - $plans = $this->dao->select('id, title')->from(TABLE_PRODUCTPLAN)->where('id')->in(array_keys($datas))->fetchPairs(); - foreach($datas as $planID => $data) $data->name = isset($plans[$planID]) ? $plans[$planID] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per status - * - * @access public - * @return array - */ - public function getDataOfStorysPerStatus() - { - $datas = $this->dao->select('status as name, count(status) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('status')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $status => $data) if(isset($this->lang->story->statusList[$status])) $data->name = $this->lang->story->statusList[$status]; - return $datas; - } - - /** - * Get report data of storys per stage - * - * @access public - * @return array - */ - public function getDataOfStorysPerStage() - { - $datas = $this->dao->select('stage as name, count(stage) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('stage')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $stage => $data) $data->name = $this->lang->story->stageList[$stage] != '' ? $this->lang->story->stageList[$stage] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per pri - * - * @access public - * @return array - */ - public function getDataOfStorysPerPri() - { - $datas = $this->dao->select('pri as name, count(pri) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('pri')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $pri => $data) $data->name = $this->lang->story->priList[$pri] != '' ? $this->lang->story->priList[$pri] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per estimate - * - * @access public - * @return array - */ - public function getDataOfStorysPerEstimate() - { - return $this->dao->select('estimate as name, count(estimate) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('estimate')->orderBy('value')->fetchAll(); - } - - /** - * Get report data of storys per openedBy - * - * @access public - * @return array - */ - public function getDataOfStorysPerOpenedBy() - { - $datas = $this->dao->select('openedBy as name, count(openedBy) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('openedBy')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) $data->name = isset($this->users[$account]) ? $this->users[$account] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per assignedTo - * - * @access public - * @return array - */ - public function getDataOfStorysPerAssignedTo() - { - $datas = $this->dao->select('assignedTo as name, count(assignedTo) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('assignedTo')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) $data->name = (isset($this->users[$account]) and $this->users[$account] != '') ? $this->users[$account] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per closedReason - * - * @access public - * @return array - */ - public function getDataOfStorysPerClosedReason() - { - $datas = $this->dao->select('closedReason as name, count(closedReason) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('closedReason')->orderBy('value DESC')->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $reason => $data) $data->name = $this->lang->story->reasonList[$reason] != '' ? $this->lang->story->reasonList[$reason] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of storys per change - * - * @access public - * @return array - */ - public function getDataOfStorysPerChange() - { - return $this->dao->select('(version-1) as name, count(*) as value')->from(TABLE_STORY) - ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() - ->groupBy('version')->orderBy('value')->fetchAll(); - } -} + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->findById((int)$storyID)->from(TABLE_STORY)->fetch(); + if(!$story) return false; + if(substr($story->closedDate, 0, 4) == '0000') $story->closedDate = ''; + if($version == 0) $version = $story->version; + $spec = $this->dao->select('title,spec,verify')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWhere('version')->eq($version)->fetch(); + $story->title = isset($spec->title) ? $spec->title : ''; + $story->spec = isset($spec->spec) ? $this->loadModel('file')->setImgSize($spec->spec) : ''; + $story->verify = isset($spec->verify) ? $spec->verify : ''; + $story->projects = $this->dao->select('t1.project, t2.name, t2.status') + ->from(TABLE_PROJECTSTORY)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2') + ->on('t1.project = t2.id') + ->where('t1.story')->eq($storyID) + ->orderBy('t1.project DESC') + ->fetchAll('project'); + $story->tasks = $this->dao->select('id, name, assignedTo, project, status, consumed, `left`')->from(TABLE_TASK)->where('story')->eq($storyID)->orderBy('id DESC')->fetchGroup('project'); + //$story->bugCount = $this->dao->select('COUNT(*)')->alias('count')->from(TABLE_BUG)->where('story')->eq($storyID)->fetch('count'); + //$story->caseCount = $this->dao->select('COUNT(*)')->alias('count')->from(TABLE_CASE)->where('story')->eq($storyID)->fetch('count'); + if($story->toBug) $story->toBugTitle = $this->dao->findById($story->toBug)->from(TABLE_BUG)->fetch('title'); + if($story->plan) $story->planTitle = $this->dao->findById($story->plan)->from(TABLE_PRODUCTPLAN)->fetch('title'); + $extraStories = array(); + if($story->duplicateStory) $extraStories = array($story->duplicateStory); + if($story->linkStories) $extraStories = explode(',', $story->linkStories); + if($story->childStories) $extraStories = array_merge($extraStories, explode(',', $story->childStories)); + $extraStories = array_unique($extraStories); + if(!empty($extraStories)) $story->extraStories = $this->dao->select('id,title')->from(TABLE_STORY)->where('id')->in($extraStories)->fetchPairs(); + return $story; + } + + /** + * Get affected things. + * + * @param object $story + * @access public + * @return object + */ + public function getAffectedScope($story) + { + /* Remove closed projects. */ + if($story->projects) + { + foreach($story->projects as $projectID => $project) + { + if($project->status != 'doing') unset($story->projects[$projectID]); + } + } + + /* Get team members. */ + if($story->projects) + { + $story->teams = $this->dao->select('account, project') + ->from(TABLE_TEAM) + ->where('project')->in(array_keys($story->projects)) + ->fetchGroup('project'); + } + + /* Get affected bugs. */ + $story->bugs = $this->dao->findByStory($story->id)->from(TABLE_BUG) + ->andWhere('status')->ne('closed') + ->andWhere('deleted')->eq(0) + ->orderBy('id desc')->fetchAll(); + + /* Get affected cases. */ + $story->cases = $this->dao->findByStory($story->id)->from(TABLE_CASE)->andWhere('deleted')->eq(0)->fetchAll(); + + return $story; + } + + /** + * Create a story. + * + * @access public + * @return int|bool the id of the created story or false when error. + */ + public function create($projectID = 0, $bugID = 0) + { + $now = helper::now(); + $story = fixer::input('post') + ->cleanInt('product,module,pri,plan') + ->cleanFloat('estimate') + ->stripTags('title') + ->callFunc('title', 'trim') + ->setDefault('plan', 0) + ->add('openedBy', $this->app->user->account) + ->add('openedDate', $now) + ->add('assignedDate', 0) + ->add('version', 1) + ->add('status', 'draft') + ->setIF($this->post->assignedTo != '', 'assignedDate', $now) + ->setIF($this->post->needNotReview, 'status', 'active') + ->setIF($this->post->plan > 0, 'stage', 'planned') + ->setIF($projectID > 0, 'stage', 'projected') + ->setIF($bugID > 0, 'fromBug', $bugID) + ->remove('files,labels,spec,verify,needNotReview') + ->get(); + + $this->dao->insert(TABLE_STORY)->data($story)->autoCheck()->batchCheck($this->config->story->create->requiredFields, 'notempty')->exec(); + if(!dao::isError()) + { + $storyID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('story', $storyID, $extra = 1); + + $data->story = $storyID; + $data->version = 1; + $data->title = $story->title; + $data->spec = $this->post->spec; + $data->verify = $this->post->verify; + $this->dao->insert(TABLE_STORYSPEC)->data($data)->exec(); + + if($projectID != 0) + { + $this->dao->insert(TABLE_PROJECTSTORY) + ->set('company')->eq(1) + ->set('project')->eq($projectID) + ->set('product')->eq($this->post->product) + ->set('story')->eq($storyID) + ->set('version')->eq(1) + ->exec(); + } + + if($bugID > 0) + { + $bug->toStory = $storyID; + $bug->status = 'closed'; + $bug->resolution = 'tostory'; + $bug->resolvedBy = $this->app->user->account; + $bug->resolvedDate = $now; + $bug->closedBy = $this->app->user->account; + $bug->closedDate = $now; + $bug->assignedTo = 'closed'; + $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec(); + + $this->loadModel('action')->create('bug', $bugID, 'ToStory', '', $storyID); + $this->action->create('bug', $bugID, 'Closed'); + + /* add files to story from bug. */ + $files = $this->dao->select('*')->from(TABLE_FILE) + ->where('objectType')->eq('bug') + ->andWhere('objectID')->eq($bugID) + ->fetchAll(); + if(!empty($files)) + { + foreach($files as $file) + { + $file->objectType = 'story'; + $file->objectID = $storyID; + unset($file->id); + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + } + } + } + return $storyID; + } + return false; + } + + /** + * Create a batch stories. + * + * @access public + * @return int|bool the id of the created story or false when error. + */ + public function batchCreate($productID = 0) + { + $now = helper::now(); + $stories = fixer::input('post')->get(); + for($i = 0; $i < $this->config->story->batchCreate; $i++) + { + if($stories->title[$i] != '') + { + $data[$i]->module = $stories->module[$i] != 'same' ? $stories->module[$i] : ($i == 0 ? 0 : $data[$i-1]->module); + $data[$i]->plan = $stories->plan[$i] == 'same' ? ($i != 0 ? $data[$i-1]->plan : 0) : ($stories->plan[$i] != '' ? $stories->plan[$i] : 0); + $data[$i]->title = $stories->title[$i]; + $data[$i]->pri = $stories->pri[$i] != '' ? $stories->pri[$i] : 0; + $data[$i]->estimate = $stories->estimate[$i] != '' ? $stories->estimate[$i] : 0; + $data[$i]->status = $stories->needReview[$i] == 0 ? 'active' : 'draft'; + $data[$i]->product = $productID; + $data[$i]->openedBy = $this->app->user->account; + $data[$i]->openedDate = $now; + $data[$i]->version = 1; + + $this->dao->insert(TABLE_STORY) + ->data($data[$i]) + ->autoCheck() + ->batchCheck($this->config->story->create->requiredFields, 'notempty') + ->exec(); + if(dao::isError()) + { + echo js::error(dao::getError()); + die(js::reload('parent')); + } + + $storyID = $this->dao->lastInsertID(); + + $specData[$i]->story = $storyID; + $specData[$i]->version = 1; + $specData[$i]->title = $stories->title[$i]; + if($stories->spec[$i] != '') $specData[$i]->spec = $stories->spec[$i]; + $this->dao->insert(TABLE_STORYSPEC)->data($specData[$i])->exec(); + + $this->loadModel('action'); + $actionID = $this->action->create('story', $storyID, 'Opened', ''); + $mails[$i]->storyID = $storyID; + $mails[$i]->actionID = $actionID; + } + else + { + unset($stories->use[$i]); + unset($stories->module[$i]); + unset($stories->plan[$i]); + unset($stories->title[$i]); + unset($stories->spec[$i]); + unset($stories->pri[$i]); + unset($stories->estimate[$i]); + unset($stories->needReview[$i]); + } + } + return $mails; + } + + /** + * Change a story. + * + * @param int $storyID + * @access public + * @return array the change of the story. + */ + public function change($storyID) + { + $now = helper::now(); + $oldStory = $this->getById($storyID); + $specChanged = false; + if($this->post->spec != $oldStory->spec or $this->post->verify != $oldStory->verify or $this->post->title != $oldStory->title or $this->loadModel('file')->getCount()) $specChanged = true; + + $story = fixer::input('post') + ->stripTags('title') + ->callFunc('title', 'trim') + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setIF($this->post->assignedTo != $oldStory->assignedTo, 'assignedDate', $now) + ->setIF($specChanged, 'version', $oldStory->version + 1) + ->setIF($specChanged and $oldStory->status == 'active' and $this->post->needNotReview == false, 'status', 'changed') + ->setIF($specChanged and $oldStory->status == 'draft' and $this->post->needNotReview, 'status', 'active') + ->setIF($specChanged, 'reviewedBy', '') + ->setIF($specChanged, 'closedBy', '') + ->setIF($specChanged, 'closedReason', '') + ->setIF($specChanged and $oldStory->reviewedBy, 'reviewedDate', '0000-00-00') + ->setIF($specChanged and $oldStory->closedBy, 'closedDate', '0000-00-00') + ->remove('files,labels,spec,verify,comment,needNotReview') + ->get(); + $this->dao->update(TABLE_STORY) + ->data($story) + ->autoCheck() + ->batchCheck($this->config->story->change->requiredFields, 'notempty') + ->where('id')->eq((int)$storyID)->exec(); + if(!dao::isError()) + { + if($specChanged) + { + $data->story = $storyID; + $data->version = $oldStory->version + 1; + $data->title = $story->title; + $data->spec = $this->post->spec; + $data->verify = $this->post->verify; + $this->dao->insert(TABLE_STORYSPEC)->data($data)->exec(); + $story->spec = $this->post->spec; + $story->verify = $this->post->verify; + } + else + { + unset($oldStory->spec); + } + return common::createChanges($oldStory, $story); + } + } + + /** + * Update a story. + * + * @param int $storyID + * @access public + * @return array the changes of the story. + */ + public function update($storyID) + { + $now = helper::now(); + $oldStory = $this->getById($storyID); + + $story = fixer::input('post') + ->cleanInt('product,module,pri,plan') + ->stripTags('title') + ->add('assignedDate', $oldStory->assignedDate) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setDefault('plan', 0) + ->setDefault('status', $oldStory->status) + ->setIF($this->post->assignedTo != $oldStory->assignedTo, 'assignedDate', $now) + ->setIF($this->post->closedBy != false and $oldStory->closedDate == '', 'closedDate', $now) + ->setIF($this->post->closedReason != false and $oldStory->closedDate == '', 'closedDate', $now) + ->setIF($this->post->closedBy != false or $this->post->closedReason != false, 'status', 'closed') + ->setIF($this->post->closedReason != false and $this->post->closedBy == false, 'closedBy', $this->app->user->account) + ->remove('files,labels,comment') + ->get(); + + $this->dao->update(TABLE_STORY) + ->data($story) + ->autoCheck() + ->batchCheck($this->config->story->edit->requiredFields, 'notempty') + ->checkIF(isset($story->closedBy), 'closedReason', 'notempty') + ->checkIF(isset($story->closedReason) and $story->closedReason == 'done', 'stage', 'notempty') + ->checkIF(isset($story->closedReason) and $story->closedReason == 'duplicate', 'duplicateStory', 'notempty') + ->checkIF(isset($story->closedReason) and $story->closedReason == 'subdivided', 'childStories', 'notempty') + ->where('id')->eq((int)$storyID)->exec(); + + if(!dao::isError()) return common::createChanges($oldStory, $story); + } + + /** + * Review a story. + * + * @param int $storyID + * @access public + * @return bool + */ + public function review($storyID) + { + if($this->post->result == false) die(js::alert($this->lang->story->mustChooseResult)); + if($this->post->result == 'revert' and $this->post->preVersion == false) die(js::alert($this->lang->story->mustChoosePreVersion)); + + $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); + $now = helper::now(); + $date = helper::today(); + $story = fixer::input('post') + ->remove('result,preVersion,comment') + ->setDefault('reviewedDate', $date) + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->setIF($this->post->result == 'pass' and $oldStory->status == 'draft', 'status', 'active') + ->setIF($this->post->result == 'pass' and $oldStory->status == 'changed', 'status', 'active') + ->setIF($this->post->result == 'reject', 'closedBy', $this->app->user->account) + ->setIF($this->post->result == 'reject', 'closedDate', $now) + ->setIF($this->post->result == 'reject', 'assignedTo', 'closed') + ->setIF($this->post->result == 'reject', 'status', 'closed') + ->setIF($this->post->result == 'revert', 'version', $this->post->preVersion) + ->setIF($this->post->result == 'revert', 'status', 'active') + ->setIF($this->post->closedReason == 'done', 'stage', 'released') + ->removeIF($this->post->result != 'reject', 'closedReason, duplicateStory, childStories') + ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'duplicate', 'duplicateStory') + ->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'subdivided', 'childStories') + ->get(); + $this->dao->update(TABLE_STORY)->data($story) + ->autoCheck() + ->batchCheck($this->config->story->review->requiredFields, 'notempty') + ->checkIF($this->post->result == 'reject', 'closedReason', 'notempty') + ->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'duplicate', 'duplicateStory', 'notempty') + ->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'subdivided', 'childStories', 'notempty') + ->where('id')->eq($storyID)->exec(); + if($this->post->result == 'revert') + { + $preTitle = $this->dao->select('title')->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWHere('version')->eq($this->post->preVersion)->fetch('title'); + $this->dao->update(TABLE_STORY)->set('title')->eq($preTitle)->where('id')->eq($storyID)->exec(); + $this->dao->delete()->from(TABLE_STORYSPEC)->where('story')->eq($storyID)->andWHere('version')->eq($oldStory->version)->exec(); + $this->dao->delete()->from(TABLE_FILE)->where('objectType')->eq('story')->andWhere('objectID')->eq($storyID)->andWhere('extra')->eq($oldStory->version)->exec(); + } + $this->setStage($storyID); + return true; + } + + /** + * Close a story. + * + * @param int $storyID + * @access public + * @return bool + */ + public function close($storyID) + { + $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); + $now = helper::now(); + $story = fixer::input('post') + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->add('closedDate', $now) + ->add('closedBy', $this->app->user->account) + ->add('assignedTo', 'closed') + ->add('assignedDate', $now) + ->add('status', 'closed') + ->removeIF($this->post->closedReason != 'duplicate', 'duplicateStory') + ->removeIF($this->post->closedReason != 'subdivided', 'childStories') + ->setIF($this->post->closedReason == 'done', 'stage', 'released') + ->setIF($this->post->closedReason != 'done', 'plan', 0) + ->remove('comment') + ->get(); + $this->dao->update(TABLE_STORY)->data($story) + ->autoCheck() + ->batchCheck($this->config->story->close->requiredFields, 'notempty') + ->checkIF($story->closedReason == 'duplicate', 'duplicateStory', 'notempty') + ->checkIF($story->closedReason == 'subdivided', 'childStories', 'notempty') + ->where('id')->eq($storyID)->exec(); + return true; + } + + /** + * Activate a story. + * + * @param int $storyID + * @access public + * @return bool + */ + public function activate($storyID) + { + $oldStory = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch(); + $now = helper::now(); + $story = fixer::input('post') + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->add('assignedDate', $now) + ->add('status', 'active') + ->add('closedBy', '') + ->add('closedReason', '') + ->add('closedDate', '0000-00-00') + ->add('reviewedBy', '') + ->add('reviewedDate', '0000-00-00') + ->remove('comment') + ->get(); + $this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq($storyID)->exec(); + return true; + } + + /** + * Set stage of a story. + * + * @param int $storyID + * @param string $customStage + * @access public + * @return bool + */ + public function setStage($storyID, $customStage = '') + { + /* Custom stage defined, use it. */ + if($customStage) + { + $this->dao->update(TABLE_STORY)->set('stage')->eq($customStage)->where('id')->eq((int)$storyID)->exec(); + return true; + } + + /* Get projects which status is doing. */ + $projects = $this->dao->select('project') + ->from(TABLE_PROJECTSTORY)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.story')->eq((int)$storyID) + ->andWhere('t2.status')->ne('done') + ->andWhere('t2.deleted')->eq(0) + ->fetchPairs(); + + /* If no projects, in plan, stage is planned. No plan, wait. */ + if(!$projects) + { + $this->dao->update(TABLE_STORY)->set('stage')->eq('planned')->where('id')->eq((int)$storyID)->andWhere('plan')->gt(0)->exec(); + $this->dao->update(TABLE_STORY)->set('stage')->eq('wait')->where('id')->eq((int)$storyID)->andWhere('plan')->eq(0)->andWhere('status')->eq('active')->exec(); + return true; + } + + /* Search related tasks. */ + $tasks = $this->dao->select('type,status')->from(TABLE_TASK) + ->where('project')->in($projects) + ->andWhere('story')->eq($storyID) + ->andWhere('status')->ne('cancel') + ->andWhere('status')->ne('closed') + ->andWhere('deleted')->eq(0) + ->fetchGroup('type'); + + /* No tasks, then the stage is projected. */ + if(!$tasks) + { + $this->dao->update(TABLE_STORY)->set('stage')->eq('projected')->where('id')->eq((int)$storyID)->exec(); + return true; + } + + /* If have test task, the stage is tested, testing or developing. */ + if(isset($tasks['test'])) + { + $stage = 'tested'; + foreach($tasks['test'] as $task) + { + if($task->status != 'done') + { + $stage = 'testing'; + break; + } + } + if($stage != 'testing') + { + unset($tasks['test']); + foreach($tasks as $type => $typeTasks) + { + foreach($typeTasks as $task) + { + if($task->status != 'done') + { + $stage = 'developing'; + break; + } + } + } + } + } + /* No test taske, stage is done or developing. */ + else + { + $stage = 'developed'; + foreach($tasks as $type => $typeTasks) + { + foreach($typeTasks as $task) + { + if($task->status != 'done') + { + $stage = 'developing'; + break; + } + } + } + } + $this->dao->update(TABLE_STORY)->set('stage')->eq($stage)->where('id')->eq((int)$storyID)->exec(); + return; + } + + /** + * Get stories list of a product. + * + * @param int $productID + * @param array|string $moduleIds + * @param string $status + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getProductStories($productID = 0, $moduleIds = 0, $status = 'all', $orderBy = 'id_desc', $pager = null) + { + $stories = $this->dao->select('t1.*, t2.title as planTitle') + ->from(TABLE_STORY)->alias('t1') + ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') + ->where('t1.product')->in($productID) + ->beginIF(!empty($moduleIds))->andWhere('module')->in($moduleIds)->fi() + ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() + ->andWhere('t1.deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + + $this->saveReportQuery($this->dao->get()); + + return $stories; + } + + /** + * Get stories pairs of a product. + * + * @param int $productID + * @param array|string $moduleIds + * @param string $status + * @param string $order + * @access public + * @return array + */ + public function getProductStoryPairs($productID = 0, $moduleIds = 0, $status = 'all', $order = 'id_desc') + { + $stories = $this->dao->select('t1.id, t1.title, t1.module, t1.pri, t1.estimate, t2.name AS product') + ->from(TABLE_STORY)->alias('t1')->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') + ->where('1=1') + ->beginIF($productID)->andWhere('t1.product')->in($productID)->fi() + ->beginIF($moduleIds)->andWhere('t1.module')->in($moduleIds)->fi() + ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() + ->andWhere('t1.deleted')->eq(0) + ->orderBy($order) + ->fetchAll(); + if(!$stories) return array(); + return $this->formatStories($stories); + } + + /** + * Get stories by assignedTo. + * + * @param int $productID + * @param string $account + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByAssignedTo($productID, $account, $orderBy, $pager) + { + return $this->getByField($productID, 'assignedTo', $account, $orderBy, $pager); + } + + /** + * Get stories by openedBy. + * + * @param int $productID + * @param string $account + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByOpenedBy($productID, $account, $orderBy, $pager) + { + return $this->getByField($productID, 'openedBy', $account, $orderBy, $pager); + } + + /** + * Get stories by reviewedBy. + * + * @param int $productID + * @param string $account + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getByReviewedBy($productID, $account, $orderBy, $pager) + { + return $this->getByField($productID, 'reviewedBy', $account, $orderBy, $pager, 'include'); + } + + /** + * Get stories by closedBy. + * + * @param int $productID + * @param string $account + * @param string $orderBy + * @param object $pager + * @return array + */ + public function getByClosedBy($productID, $account, $orderBy, $pager) + { + return $this->getByField($productID, 'closedBy', $account, $orderBy, $pager); + } + + /** + * Get stories by status. + * + * @param int $productID + * @param string $orderBy + * @param object $pager + * @param string $status + * @access public + * @return array + */ + public function getByStatus($productID, $status, $orderBy, $pager) + { + return $this->getByField($productID, 'status', $status, $orderBy, $pager); + } + + /** + * Get stories by a field. + * + * @param int $productID + * @param string $fieldName + * @param mixed $fieldValue + * @param string $orderBy + * @param object $pager + * @param string $operator equal|include + * @access public + * @return array + */ + public function getByField($productID, $fieldName, $fieldValue, $orderBy, $pager, $operator = 'equal') + { + $stories = $this->dao->select('t1.*, t2.title as planTitle') + ->from(TABLE_STORY)->alias('t1') + ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') + ->where('t1.product')->in($productID) + ->andWhere('t1.deleted')->eq(0) + ->beginIF($operator == 'equal')->andWhere($fieldName)->eq($fieldValue)->fi() + ->beginIF($operator == 'include')->andWhere($fieldName)->like("%$fieldValue%")->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + $this->saveReportQuery($this->dao->get()); + + return $stories; + } + + /** + * Get stories through search. + * + * @access public + * @param int $productID + * @param int $queryID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getBySearch($productID, $queryID, $orderBy, $pager) + { + $products = $this->loadModel('product')->getPairs(); + $query = $queryID ? $this->loadModel('search')->getQuery($queryID) : ''; + + /* Get the sql and form status from the query. */ + if($query) + { + $this->session->set('storyQuery', $query->sql); + $this->session->set('storyForm', $query->form); + } + if($this->session->storyQuery == false) $this->session->set('storyQuery', ' 1 = 1'); + + $allProduct = "`product` = 'all'"; + $storyQuery = $this->session->storyQuery; + $queryProductID = $productID; + if(strpos($this->session->storyQuery, $allProduct) !== false) + { + $storyQuery = str_replace($allProduct, '1', $this->session->storyQuery); + $queryProductID = 'all'; + } + $storyQuery = $storyQuery . 'AND `product`' . helper::dbIN(array_keys($products)); + + return $this->getBySQL($queryProductID, $storyQuery, $orderBy, $pager); + } + + /** + * Get stories by a sql. + * + * @param int $productID + * @param string $sql + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getBySQL($productID, $sql, $orderBy, $pager = null) + { + $tmpStories = $this->dao->select('*')->from(TABLE_STORY)->where($sql) + ->beginIF($productID != 'all')->andWhere('product')->eq((int)$productID)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + $this->saveReportQuery($this->dao->get()); + + if(!$tmpStories) return array(); + + /* Get plans. */ + $plans = array(); + foreach($tmpStories as $story) $plans[$story->plan] = $story->plan; + $plans = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)->where('id')->in(array_keys($plans))->fetchPairs(); + + /* Process plans. */ + $stories = array(); + foreach($tmpStories as $story) + { + $story->planTitle = isset($plans[$story->plan]) ? $plans[$story->plan] : ''; + $stories[] = $story; + } + return $stories; + } + + /** + * Save one executed query as report query, thus when create report chart to make use the condition is the same. + * + * @param string $sql + * @access public + * @return void + */ + public function saveReportQuery($sql) + { + $sql = explode('WHERE', $sql); + $sql = explode('ORDER', $sql[1]); + $sql = str_replace('t1.', '', $sql[0]); + $this->session->set('storyReport', $sql); + } + + /** + * Get stories list of a project. + * + * @param int $projectID + * @param string $orderBy + * @access public + * @return array + */ + public function getProjectStories($projectID = 0, $orderBy = 'pri_asc,id_desc') + { + return $this->dao->select('t1.*, t2.*')->from(TABLE_PROJECTSTORY)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t2.deleted')->eq(0) + ->orderBy($orderBy) + ->fetchAll('id'); + } + + /** + * Get stories pairs of a project. + * + * @param int $projectID + * @param int $productID + * @access public + * @return array + */ + public function getProjectStoryPairs($projectID = 0, $productID = 0) + { + $stories = $this->dao->select('t2.id, t2.title, t2.module, t2.pri, t2.estimate, t3.name AS product') + ->from(TABLE_PROJECTSTORY)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2') + ->on('t1.story = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3') + ->on('t1.product = t3.id') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t2.deleted')->eq(0) + ->beginIF($productID)->andWhere('t1.product')->eq((int)$productID)->fi() + ->fetchAll(); + if(!$stories) return array(); + return $this->formatStories($stories); + } + + /** + * Get stories list of a plan. + * + * @param int $planID + * @param string $status + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getPlanStories($planID, $status = 'all', $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_STORY) + ->where('plan')->eq((int)$planID) + ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll('id'); + } + + /** + * Get stories pairs of a plan. + * + * @param int $planID + * @param string $status + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getPlanStoryPairs($planID, $status = 'all', $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_STORY) + ->where('plan')->eq($planID) + ->beginIF($status != 'all')->andWhere('status')->in($status)->fi() + ->andWhere('deleted')->eq(0) + ->fetchAll(); + } + + /** + * Get stories of a user. + * + * @param string $account + * @param string $type the query type + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getUserStories($account, $type = 'assignedto', $orderBy = 'id_desc', $pager = null) + { + $type = strtolower($type); + return $this->dao->select('t1.*, t2.title as planTitle, t3.name as productTitle') + ->from(TABLE_STORY)->alias('t1') + ->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id') + ->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id') + ->where('t1.deleted')->eq(0) + ->beginIF($type == 'assignedto')->andWhere('assignedTo')->eq($this->app->user->account)->fi() + ->beginIF($type == 'openedby')->andWhere('openedby')->eq($this->app->user->account)->fi() + ->beginIF($type == 'reviewedby')->andWhere('reviewedby')->like('%' . $this->app->user->account . '%')->fi() + ->beginIF($type == 'closedby')->andWhere('closedby')->eq($this->app->user->account)->fi() + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get doing projects' members of a story. + * + * @param int $storyID + * @access public + * @return array + */ + public function getProjectMembers($storyID) + { + $projects = $this->dao->select('project') + ->from(TABLE_PROJECTSTORY)->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.story')->eq((int)$storyID) + ->andWhere('t2.status')->eq('doing') + ->andWhere('t2.deleted')->eq(0) + ->fetchPairs(); + if($projects) return($this->dao->select('account')->from(TABLE_TEAM)->where('project')->in($projects)->fetchPairs('account')); + } + + /** + * Get version of a story. + * + * @param int $storyID + * @access public + * @return int + */ + public function getVersion($storyID) + { + return $this->dao->select('version')->from(TABLE_STORY)->where('id')->eq((int)$storyID)->fetch('version'); + } + + /** + * Get versions of some stories. + * + * @param array|string story id list + * @access public + * @return array + */ + public function getVersions($storyID) + { + return $this->dao->select('id, version')->from(TABLE_STORY)->where('id')->in($storyID)->fetchPairs(); + } + + /** + * Format stories + * + * @param array $stories + * @access public + * @return void + */ + public function formatStories($stories) + { + /* Get module names of stories. */ + /*$modules = array(); + foreach($stories as $story) $modules[] = $story->module; + $moduleNames = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($modules)->fetchPairs();*/ + + /* Format these stories. */ + $storyPairs = array('' => ''); + foreach($stories as $story) $storyPairs[$story->id] = $story->id . ':' . $story->title . "({$this->lang->story->pri}:$story->pri, {$this->lang->story->estimate}: $story->estimate)"; + return $storyPairs; + } + + /** + * Extract accounts from some stories. + * + * @param array $stories + * @access public + * @return array + */ + public function extractAccountsFromList($stories) + { + $accounts = array(); + foreach($stories as $story) + { + if(!empty($story->openedBy)) $accounts[] = $story->openedBy; + if(!empty($story->assignedTo)) $accounts[] = $story->assignedTo; + if(!empty($story->closedBy)) $accounts[] = $story->closedBy; + if(!empty($story->lastEditedBy)) $accounts[] = $story->lastEditedBy; + } + return array_unique($accounts); + } + + /** + * Extract accounts from a story. + * + * @param object $story + * @access public + * @return array + */ + public function extractAccountsFromSingle($story) + { + $accounts = array(); + if(!empty($story->openedBy)) $accounts[] = $story->openedBy; + if(!empty($story->assignedTo)) $accounts[] = $story->assignedTo; + if(!empty($story->closedBy)) $accounts[] = $story->closedBy; + if(!empty($story->lastEditedBy)) $accounts[] = $story->lastEditedBy; + return array_unique($accounts); + } + + /** + * Merge the default chart settings and the settings of current chart. + * + * @param string $chartType + * @access public + * @return void + */ + public function mergeChartOption($chartType) + { + $chartOption = $this->lang->story->report->$chartType; + $commonOption = $this->lang->story->report->options; + + $chartOption->graph->caption = $this->lang->story->report->charts[$chartType]; + if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; + if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; + if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; + + foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; + } + + /** + * Get report data of storys per product + * + * @access public + * @return array + */ + public function getDataOfStorysPerProduct() + { + $datas = $this->dao->select('product as name, count(product) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('product')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $products = $this->loadModel('product')->getPairs(); + foreach($datas as $productID => $data) $data->name = isset($products[$productID]) ? $products[$productID] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per module + * + * @access public + * @return array + */ + public function getDataOfStorysPerModule() + { + $datas = $this->dao->select('module as name, count(module) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('module')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $modules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in(array_keys($datas))->fetchPairs(); + foreach($datas as $moduleID => $data) $data->name = isset($modules[$moduleID]) ? $modules[$moduleID] : '/'; + return $datas; + } + + /** + * Get report data of storys per source + * + * @access public + * @return array + */ + public function getDataOfStorysPerSource() + { + $datas = $this->dao->select('source as name, count(source) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('source')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $this->lang->story->sourceList[''] = $this->lang->report->undefined; + foreach($datas as $key => $data) $data->name = isset($this->lang->story->sourceList[$key]) ? $this->lang->story->sourceList[$key] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per plan + * + * @access public + * @return array + */ + public function getDataOfStorysPerPlan() + { + $datas = $this->dao->select('plan as name, count(plan) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('plan')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + $plans = $this->dao->select('id, title')->from(TABLE_PRODUCTPLAN)->where('id')->in(array_keys($datas))->fetchPairs(); + foreach($datas as $planID => $data) $data->name = isset($plans[$planID]) ? $plans[$planID] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per status + * + * @access public + * @return array + */ + public function getDataOfStorysPerStatus() + { + $datas = $this->dao->select('status as name, count(status) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('status')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $status => $data) if(isset($this->lang->story->statusList[$status])) $data->name = $this->lang->story->statusList[$status]; + return $datas; + } + + /** + * Get report data of storys per stage + * + * @access public + * @return array + */ + public function getDataOfStorysPerStage() + { + $datas = $this->dao->select('stage as name, count(stage) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('stage')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $stage => $data) $data->name = $this->lang->story->stageList[$stage] != '' ? $this->lang->story->stageList[$stage] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per pri + * + * @access public + * @return array + */ + public function getDataOfStorysPerPri() + { + $datas = $this->dao->select('pri as name, count(pri) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('pri')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $pri => $data) $data->name = $this->lang->story->priList[$pri] != '' ? $this->lang->story->priList[$pri] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per estimate + * + * @access public + * @return array + */ + public function getDataOfStorysPerEstimate() + { + return $this->dao->select('estimate as name, count(estimate) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('estimate')->orderBy('value')->fetchAll(); + } + + /** + * Get report data of storys per openedBy + * + * @access public + * @return array + */ + public function getDataOfStorysPerOpenedBy() + { + $datas = $this->dao->select('openedBy as name, count(openedBy) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('openedBy')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) $data->name = isset($this->users[$account]) ? $this->users[$account] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per assignedTo + * + * @access public + * @return array + */ + public function getDataOfStorysPerAssignedTo() + { + $datas = $this->dao->select('assignedTo as name, count(assignedTo) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('assignedTo')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) $data->name = (isset($this->users[$account]) and $this->users[$account] != '') ? $this->users[$account] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per closedReason + * + * @access public + * @return array + */ + public function getDataOfStorysPerClosedReason() + { + $datas = $this->dao->select('closedReason as name, count(closedReason) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('closedReason')->orderBy('value DESC')->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $reason => $data) $data->name = $this->lang->story->reasonList[$reason] != '' ? $this->lang->story->reasonList[$reason] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of storys per change + * + * @access public + * @return array + */ + public function getDataOfStorysPerChange() + { + return $this->dao->select('(version-1) as name, count(*) as value')->from(TABLE_STORY) + ->beginIF($this->session->storyReport != false)->where($this->session->storyReport)->fi() + ->groupBy('version')->orderBy('value')->fetchAll(); + } +} diff --git a/module/story/view/activate.html.php b/module/story/view/activate.html.php index f88efd333e..ff0367d40b 100644 --- a/module/story/view/activate.html.php +++ b/module/story/view/activate.html.php @@ -1,36 +1,36 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - -
          story->activate;?>
          story->assignedTo;?>closedBy, 'class="select-3"');?>
          story->comment;?>
          - goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); - ?> -
          - -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + +
          story->activate;?>
          story->assignedTo;?>closedBy, 'class="select-3"');?>
          story->comment;?>
          + goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); + ?> +
          + +
          + diff --git a/module/story/view/batchcreate.html.php b/module/story/view/batchcreate.html.php index d7d63392af..dae9e6d012 100644 --- a/module/story/view/batchcreate.html.php +++ b/module/story/view/batchcreate.html.php @@ -1,49 +1,49 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - story->batchCreate; $i++):?> - - - - - - - - - - - - - - - - -
          story->product . $lang->colon . $lang->story->batchCreate;?>
          idAB;?>story->module;?>story->plan;?>story->title;?>story->spec;?>story->pri;?>story->estimate;?>story->review;?>
          *";?>story->priList, $pri, 'class=select-1');?>story->reviewList, 0, "class='text-1'");?>
          -
          story->notes;?>
          -
          -
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + story->batchCreate; $i++):?> + + + + + + + + + + + + + + + + +
          story->product . $lang->colon . $lang->story->batchCreate;?>
          idAB;?>story->module;?>story->plan;?>story->title;?>story->spec;?>story->pri;?>story->estimate;?>story->review;?>
          *";?>story->priList, $pri, 'class=select-1');?>story->reviewList, 0, "class='text-1'");?>
          +
          story->notes;?>
          +
          +
          +
          + diff --git a/module/story/view/change.html.php b/module/story/view/change.html.php index a001e8d8cb..8c88de5ead 100644 --- a/module/story/view/change.html.php +++ b/module/story/view/change.html.php @@ -1,52 +1,52 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - -
          story->change;?>
          story->reviewedBy;?>assignedTo, 'class="select-3"') . html::checkbox('needNotReview', $lang->story->needNotReview, '', "id='needNotReview'");?>
          story->title;?>title, 'class="text-1"');?>
          story->spec;?>spec), 'rows=8 class="area-1"');?>
          story->specTemplate;?>
          story->verify;?>verify), 'rows=6 class="area-1"');?>
          story->comment;?>
          attatch;?>fetch('file', 'buildform', 'filecount=2');?>
          - -
          - goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); - ?> -
          - -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + +
          story->change;?>
          story->reviewedBy;?>assignedTo, 'class="select-3"') . html::checkbox('needNotReview', $lang->story->needNotReview, '', "id='needNotReview'");?>
          story->title;?>title, 'class="text-1"');?>
          story->spec;?>spec), 'rows=8 class="area-1"');?>
          story->specTemplate;?>
          story->verify;?>verify), 'rows=6 class="area-1"');?>
          story->comment;?>
          attatch;?>fetch('file', 'buildform', 'filecount=2');?>
          + +
          + goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); + ?> +
          + +
          + diff --git a/module/story/view/close.html.php b/module/story/view/close.html.php index d5e0d39b3e..c101eef0f2 100644 --- a/module/story/view/close.html.php +++ b/module/story/view/close.html.php @@ -1,42 +1,42 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - - - - - - - - -
          title;?>
          story->closedReason;?>story->reasonList, '', 'class=select-3 onchange="setStory(this.value)"');?>
          story->comment;?>
          - - goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id"));?> -
          - -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + + + + + + + + +
          title;?>
          story->closedReason;?>story->reasonList, '', 'class=select-3 onchange="setStory(this.value)"');?>
          story->comment;?>
          + + goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id"));?> +
          + +
          + diff --git a/module/story/view/create.html.php b/module/story/view/create.html.php index 7f1bee3fd5..c088e2edfd 100644 --- a/module/story/view/create.html.php +++ b/module/story/view/create.html.php @@ -1,73 +1,73 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          story->create;?>
          story->product;?> - - -
          story->plan;?>
          story->source;?>story->sourceList, $source, 'class=select-3');?>
          story->title;?>
          story->spec;?>
          story->specTemplate;?>
          story->verify;?>
          story->pri;?>story->priList, $pri, 'class=select-3');?>
          story->estimate;?>
          story->reviewedBy;?>story->needNotReview, '', "id='needNotReview'");?>
          story->mailto;?>
          story->keywords;?>
          story->legendAttatch;?>fetch('file', 'buildform');?>
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          story->create;?>
          story->product;?> + + +
          story->plan;?>
          story->source;?>story->sourceList, $source, 'class=select-3');?>
          story->title;?>
          story->spec;?>
          story->specTemplate;?>
          story->verify;?>
          story->pri;?>story->priList, $pri, 'class=select-3');?>
          story->estimate;?>
          story->reviewedBy;?>story->needNotReview, '', "id='needNotReview'");?>
          story->mailto;?>
          story->keywords;?>
          story->legendAttatch;?>fetch('file', 'buildform');?>
          +
          + diff --git a/module/story/view/edit.html.php b/module/story/view/edit.html.php index fbe2563a95..fe99333dc1 100644 --- a/module/story/view/edit.html.php +++ b/module/story/view/edit.html.php @@ -1,139 +1,139 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          -
          STORY #id . $lang->colon . $story->title;?>
          -
          -
          - - - - - - - -
          -
          - story->legendSpec;?> -
          spec;?>
          -
          -
          - story->comment;?> - -
          -
          - goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); - ?> -
          - -
          -
          - story->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - status != 'draft'):?> - - - - - - - - - - - - - - - - - -
          story->product;?>product, 'class="select-1" onchange="loadProduct(this.value)";');?>
          story->module;?>module, 'class="select-1"');?>
          story->plan;?>plan, 'class=select-1');?>
          story->source;?>story->sourceList, $story->source, 'class=select-1');?>
          story->status;?>story->statusList[$story->status];?>
          story->stage;?>story->stageList, $story->stage, 'class=select-1');?>
          story->pri;?>story->priList, $story->pri, 'class=select-1');?>
          story->estimate;?>estimate, 'class=text-1');?>
          story->keywords;?>keywords, 'class=text-1');?>
          -
          -
          - story->legendLifeTime;?> - - - - - - - - - - reviewedBy):?> - - - - - - closedBy):?> - - - - - - - - - -
          story->openedBy;?>openedBy];?>
          story->assignedTo;?>assignedTo, 'class="select-1"');?>
          story->reviewedBy;?>reviewedBy, 'class="area-1"');?>
          story->closedBy;?>closedBy, 'class="select-1"');?>
          story->closedReason;?>story->reasonList, $story->closedReason, 'class="select-1"');?>
          -
          - -
          - story->legendMisc;?> - - - - - - - - - - - - - - - - - -
          story->duplicateStory;?>duplicateStory, "class='text-1'");?>
          story->linkStories;?>linkStories, "class='text-1'");?>
          story->childStories;?>childStories, "class='text-1'");?>
          story->mailto;?>mailto, "class='area-1'");?>
          -
          -
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +
          +
          STORY #id . $lang->colon . $story->title;?>
          +
          +
          + + + + + + + +
          +
          + story->legendSpec;?> +
          spec;?>
          +
          +
          + story->comment;?> + +
          +
          + goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id")); + ?> +
          + +
          +
          + story->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + status != 'draft'):?> + + + + + + + + + + + + + + + + + +
          story->product;?>product, 'class="select-1" onchange="loadProduct(this.value)";');?>
          story->module;?>module, 'class="select-1"');?>
          story->plan;?>plan, 'class=select-1');?>
          story->source;?>story->sourceList, $story->source, 'class=select-1');?>
          story->status;?>story->statusList[$story->status];?>
          story->stage;?>story->stageList, $story->stage, 'class=select-1');?>
          story->pri;?>story->priList, $story->pri, 'class=select-1');?>
          story->estimate;?>estimate, 'class=text-1');?>
          story->keywords;?>keywords, 'class=text-1');?>
          +
          +
          + story->legendLifeTime;?> + + + + + + + + + + reviewedBy):?> + + + + + + closedBy):?> + + + + + + + + + +
          story->openedBy;?>openedBy];?>
          story->assignedTo;?>assignedTo, 'class="select-1"');?>
          story->reviewedBy;?>reviewedBy, 'class="area-1"');?>
          story->closedBy;?>closedBy, 'class="select-1"');?>
          story->closedReason;?>story->reasonList, $story->closedReason, 'class="select-1"');?>
          +
          + +
          + story->legendMisc;?> + + + + + + + + + + + + + + + + + +
          story->duplicateStory;?>duplicateStory, "class='text-1'");?>
          story->linkStories;?>linkStories, "class='text-1'");?>
          story->childStories;?>childStories, "class='text-1'");?>
          story->mailto;?>mailto, "class='area-1'");?>
          +
          +
          +
          + diff --git a/module/story/view/export.html.php b/module/story/view/export.html.php index e832c5cd50..c6680aa28f 100644 --- a/module/story/view/export.html.php +++ b/module/story/view/export.html.php @@ -1,13 +1,13 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + diff --git a/module/story/view/report.html.php b/module/story/view/report.html.php index 24e8d7a59f..1e812e36bf 100644 --- a/module/story/view/report.html.php +++ b/module/story/view/report.html.php @@ -1,62 +1,62 @@ - - * @package product - * @version $Id: report.html.php 1594 2011-03-13 07:27:55Z wwccss $ - * @link http://www.zentao.net - */ -?> - -
          -
          story->report->common;?>
          -
          goback); ?>
          -
          - - - - - - - -
          -
          story->report->select;?>
          -
          -
          - story->report->charts, $checkedCharts);?> - - -

          - story->report->create);?> -
          -
          - - - $chartContent):?> - - - - - -
          story->report->common;?>
          - - - - - - - $data):?> - - - - - - -
          report->item;?>report->value;?>report->percent;?>
          name;?>value;?>percent * 100) . '%';?>
          -
          -
          - - + + * @package product + * @version $Id: report.html.php 1594 2011-03-13 07:27:55Z wwccss $ + * @link http://www.zentao.net + */ +?> + +
          +
          story->report->common;?>
          +
          goback); ?>
          +
          + + + + + + + +
          +
          story->report->select;?>
          +
          + + story->report->charts, $checkedCharts);?> + + +

          + story->report->create);?> +
          +
          + + + $chartContent):?> + + + + + +
          story->report->common;?>
          + + + + + + + $data):?> + + + + + + +
          report->item;?>report->value;?>report->percent;?>
          name;?>value;?>percent * 100) . '%';?>
          +
          +
          + + diff --git a/module/story/view/review.html.php b/module/story/view/review.html.php index d6fe8888df..554d6eaef3 100644 --- a/module/story/view/review.html.php +++ b/module/story/view/review.html.php @@ -1,68 +1,68 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - status == 'changed' or ($story->status == 'draft' and $story->version > 1)):?> - - - - - - - - - - - - - - - - - - - - -
          title;?>
          story->reviewedDate;?>
          story->reviewResult;?>story->reviewResultList, '', 'class=select-3 onchange="switchShow(this.value)"');?>
          story->assignedTo;?>lastEditedBy ? $story->lastEditedBy : $story->openedBy, 'class=select-3');?>
          story->reviewedBy;?>user->account . ', ', 'class=text-1');?>
          story->comment;?>
          - - goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id"));?> -
          - - - - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + status == 'changed' or ($story->status == 'draft' and $story->version > 1)):?> + + + + + + + + + + + + + + + + + + + + +
          title;?>
          story->reviewedDate;?>
          story->reviewResult;?>story->reviewResultList, '', 'class=select-3 onchange="switchShow(this.value)"');?>
          story->assignedTo;?>lastEditedBy ? $story->lastEditedBy : $story->openedBy, 'class=select-3');?>
          story->reviewedBy;?>user->account . ', ', 'class=text-1');?>
          story->comment;?>
          + + goback, $app->session->storyList ? $app->session->storyList : inlink('view', "storyID=$story->id"));?> +
          +
          + + + diff --git a/module/story/view/sendmail.html.php b/module/story/view/sendmail.html.php index 249a603dca..077669f161 100644 --- a/module/story/view/sendmail.html.php +++ b/module/story/view/sendmail.html.php @@ -1,22 +1,22 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          - STORY #id . "=>$story->assignedTo " . html::a(common::getSysURL() . $this->createLink('story', 'view', "storyID=$story->id"), $story->title);?> -
          + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          + STORY #id . "=>$story->assignedTo " . html::a(common::getSysURL() . $this->createLink('story', 'view', "storyID=$story->id"), $story->title);?> +
          diff --git a/module/story/view/view.html.php b/module/story/view/view.html.php index 9b9695d83c..0b45ce3416 100644 --- a/module/story/view/view.html.php +++ b/module/story/view/view.html.php @@ -1,273 +1,273 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          deleted) echo "class='deleted'";?>>STORY #id . $lang->colon . $story->title;?>
          -
          - session->storyList != false ? $app->session->storyList : $this->createLink('product', 'browse', "productID=$story->product&moduleID=$story->module"); - if(!$story->deleted) - { - if(!($story->status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; - if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; - if(common::hasPriv('story', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; - if(!($story->status == 'closed' and $story->closedReason == 'postponed' and common::printLink('story', 'activate', "storyID=$story->id", $lang->story->activate))) echo $lang->story->activate . ' '; - if(!common::printLink('story', 'edit', "storyID=$story->id", $lang->edit)) echo $lang->edit . ' '; - if(!common::printLink('testcase', 'create', "productID=$story->product&moduleID=0&from=¶m=0&storyID=$story->id", $lang->story->createCase)) echo $lang->story->createCase . ' '; - common::printLink('story', 'create', "productID=$story->product&moduleID=$story->module&storyID=$story->id", $lang->copy); - common::printLink('story', 'delete', "storyID=$story->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          -
          - - - - - - -
          -
          - story->legendSpec;?> -
          spec;?>
          -
          -
          - story->legendVerify;?> -
          verify;?>
          -
          - fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true'));?> - -
          - deleted) - { - if(!($story->status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; - if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; - if(common::hasPriv('story', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; - if(!($story->status == 'closed' and $story->closedReason == 'postponed' and common::printLink('story', 'activate', "storyID=$story->id", $lang->story->activate))) echo $lang->story->activate . ' '; - if(!common::printLink('testcase', 'create', "productID=$story->product&moduleID=0&from=¶m=0&storyID=$story->id", $lang->story->createCase)) echo $lang->story->createCase . ' '; - if(!common::printLink('story', 'edit', "storyID=$story->id", $lang->edit)) echo $lang->edit . ' '; - common::printLink('story', 'delete', "storyID=$story->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - -
          - -
          - story->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          story->product;?>product", $product->name);?> -
          story->module;?> - $module) - { - if(!common::printLink('product', 'browse', "productID=$story->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; - if(isset($modulePath[$key + 1])) echo $lang->arrow; - } - } - ?> -
          story->plan;?>planTitle)) if(!common::printLink('productplan', 'view', "planID=$story->plan", $story->planTitle)) echo $story->planTitle;?> -
          story->source;?>story->sourceList[$story->source];?>
          story->status;?>story->statusList[$story->status];?>
          story->stage;?>story->stageList[$story->stage];?>
          story->pri;?>story->priList[$story->pri];?>
          story->estimate;?>estimate;?>
          story->keywords;?>keywords;?>
          -
          -
          - story->legendLifeTime;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          story->openedBy;?>openedBy] . $lang->at . $story->openedDate;?>
          story->assignedTo;?>assignedTo) echo $users[$story->assignedTo] . $lang->at . $story->assignedDate;?>
          story->reviewedBy;?>reviewedBy); foreach($reviewedBy as $account) echo ' ' . $users[trim($account)]; ?>
          story->reviewedDate;?>reviewedBy) echo $story->reviewedDate;?>
          story->closedBy;?>closedBy) echo $users[$story->closedBy] . $lang->at . $story->closedDate;?>
          story->closedReason;?> - closedReason) echo $lang->story->reasonList[$story->closedReason]; - if(isset($story->extraStories[$story->duplicateStory])) - { - echo html::a(inlink('view', "storyID=$story->duplicateStory"), '#' . $story->duplicateStory . ' ' . $story->extraStories[$story->duplicateStory]); - } - ?> -
          story->lastEditedBy;?>lastEditedBy) echo $users[$story->lastEditedBy] . $lang->at . $story->lastEditedDate;?>
          -
          - -
          - story->legendProjectAndTask;?> - - - - -
          - tasks as $projectTasks) - { - foreach($projectTasks as $task) - { - @$projectName = $story->projects[$task->project]->name; - echo html::a($this->createLink('project', 'browse', "projectID=$task->project"), $projectName); - echo '' . html::a($this->createLink('task', 'view', "taskID=$task->id"), "#$task->id $task->name") . '
          '; - } - } - ?> -
          -
          - -
          - story->legendBugs;?> - - - - -
          - ' . html::a($this->createLink('bug', 'view', "bugID=$bug->id"), "#$bug->id $bug->title") . '
          '; - } - ?> -
          -
          - -
          - story->legendCases;?> - - - - -
          - ' . html::a($this->createLink('testcase', 'view', "caseID=$case->id"), "#$case->id $case->title") . '
          '; - } - ?> -
          -
          - -
          - story->legendLinkStories;?> -
          - linkStories) ; - foreach($linkStories as $linkStoryID) - { - if(isset($story->extraStories[$linkStoryID])) echo html::a(inlink('view', "storyID=$linkStoryID"), "#$linkStoryID " . $story->extraStories[$linkStoryID]) . '
          '; - } - ?> -
          -
          -
          - story->legendChildStories;?> -
          - childStories) ; - foreach($childStories as $childStoryID) - { - if(isset($story->extraStories[$childStoryID])) echo html::a(inlink('view', "storyID=$childStoryID"), "#$childStoryID " . $story->extraStories[$childStoryID]) . '
          '; - } - ?> -
          -
          -
          - story->legendFromBug;?> -
          - ' . html::a($this->createLink('bug', 'view', "bugID=$fromBug->id"), "#$fromBug->id $fromBug->title") . '
          '; - ?> -
          -
          -
          - story->legendMailto;?> -
          mailto); foreach($mailto as $account) echo ' ' . $users[trim($account)]; ?>
          -
          -
          - story->legendVersion;?> -
          version; $i >= 1; $i --) echo html::a(inlink('view', "storyID=$story->id&version=$i"), "#$i");?>
          -
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +
          deleted) echo "class='deleted'";?>>STORY #id . $lang->colon . $story->title;?>
          +
          + session->storyList != false ? $app->session->storyList : $this->createLink('product', 'browse', "productID=$story->product&moduleID=$story->module"); + if(!$story->deleted) + { + if(!($story->status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; + if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; + if(common::hasPriv('story', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; + if(!($story->status == 'closed' and $story->closedReason == 'postponed' and common::printLink('story', 'activate', "storyID=$story->id", $lang->story->activate))) echo $lang->story->activate . ' '; + if(!common::printLink('story', 'edit', "storyID=$story->id", $lang->edit)) echo $lang->edit . ' '; + if(!common::printLink('testcase', 'create', "productID=$story->product&moduleID=0&from=¶m=0&storyID=$story->id", $lang->story->createCase)) echo $lang->story->createCase . ' '; + common::printLink('story', 'create', "productID=$story->product&moduleID=$story->module&storyID=$story->id", $lang->copy); + common::printLink('story', 'delete', "storyID=$story->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          +
          + + + + + + +
          +
          + story->legendSpec;?> +
          spec;?>
          +
          +
          + story->legendVerify;?> +
          verify;?>
          +
          + fetch('file', 'printFiles', array('files' => $story->files, 'fieldset' => 'true'));?> + +
          + deleted) + { + if(!($story->status != 'closed' and common::printLink('story', 'change', "storyID=$story->id", $lang->story->change))) echo $lang->story->change . ' '; + if(!(($story->status == 'draft' or $story->status == 'changed') and common::printLink('story', 'review', "storyID=$story->id", $lang->story->review))) echo $lang->story->review . ' '; + if(common::hasPriv('story', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!($story->status != 'closed' and common::printLink('story', 'close', "storyID=$story->id", $lang->story->close))) echo $lang->story->close . ' '; + if(!($story->status == 'closed' and $story->closedReason == 'postponed' and common::printLink('story', 'activate', "storyID=$story->id", $lang->story->activate))) echo $lang->story->activate . ' '; + if(!common::printLink('testcase', 'create', "productID=$story->product&moduleID=0&from=¶m=0&storyID=$story->id", $lang->story->createCase)) echo $lang->story->createCase . ' '; + if(!common::printLink('story', 'edit', "storyID=$story->id", $lang->edit)) echo $lang->edit . ' '; + common::printLink('story', 'delete', "storyID=$story->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + +
          + +
          + story->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          story->product;?>product", $product->name);?> +
          story->module;?> + $module) + { + if(!common::printLink('product', 'browse', "productID=$story->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; + if(isset($modulePath[$key + 1])) echo $lang->arrow; + } + } + ?> +
          story->plan;?>planTitle)) if(!common::printLink('productplan', 'view', "planID=$story->plan", $story->planTitle)) echo $story->planTitle;?> +
          story->source;?>story->sourceList[$story->source];?>
          story->status;?>story->statusList[$story->status];?>
          story->stage;?>story->stageList[$story->stage];?>
          story->pri;?>story->priList[$story->pri];?>
          story->estimate;?>estimate;?>
          story->keywords;?>keywords;?>
          +
          +
          + story->legendLifeTime;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          story->openedBy;?>openedBy] . $lang->at . $story->openedDate;?>
          story->assignedTo;?>assignedTo) echo $users[$story->assignedTo] . $lang->at . $story->assignedDate;?>
          story->reviewedBy;?>reviewedBy); foreach($reviewedBy as $account) echo ' ' . $users[trim($account)]; ?>
          story->reviewedDate;?>reviewedBy) echo $story->reviewedDate;?>
          story->closedBy;?>closedBy) echo $users[$story->closedBy] . $lang->at . $story->closedDate;?>
          story->closedReason;?> + closedReason) echo $lang->story->reasonList[$story->closedReason]; + if(isset($story->extraStories[$story->duplicateStory])) + { + echo html::a(inlink('view', "storyID=$story->duplicateStory"), '#' . $story->duplicateStory . ' ' . $story->extraStories[$story->duplicateStory]); + } + ?> +
          story->lastEditedBy;?>lastEditedBy) echo $users[$story->lastEditedBy] . $lang->at . $story->lastEditedDate;?>
          +
          + +
          + story->legendProjectAndTask;?> + + + + +
          + tasks as $projectTasks) + { + foreach($projectTasks as $task) + { + @$projectName = $story->projects[$task->project]->name; + echo html::a($this->createLink('project', 'browse', "projectID=$task->project"), $projectName); + echo '' . html::a($this->createLink('task', 'view', "taskID=$task->id"), "#$task->id $task->name") . '
          '; + } + } + ?> +
          +
          + +
          + story->legendBugs;?> + + + + +
          + ' . html::a($this->createLink('bug', 'view', "bugID=$bug->id"), "#$bug->id $bug->title") . '
          '; + } + ?> +
          +
          + +
          + story->legendCases;?> + + + + +
          + ' . html::a($this->createLink('testcase', 'view', "caseID=$case->id"), "#$case->id $case->title") . '
          '; + } + ?> +
          +
          + +
          + story->legendLinkStories;?> +
          + linkStories) ; + foreach($linkStories as $linkStoryID) + { + if(isset($story->extraStories[$linkStoryID])) echo html::a(inlink('view', "storyID=$linkStoryID"), "#$linkStoryID " . $story->extraStories[$linkStoryID]) . '
          '; + } + ?> +
          +
          +
          + story->legendChildStories;?> +
          + childStories) ; + foreach($childStories as $childStoryID) + { + if(isset($story->extraStories[$childStoryID])) echo html::a(inlink('view', "storyID=$childStoryID"), "#$childStoryID " . $story->extraStories[$childStoryID]) . '
          '; + } + ?> +
          +
          +
          + story->legendFromBug;?> +
          + ' . html::a($this->createLink('bug', 'view', "bugID=$fromBug->id"), "#$fromBug->id $fromBug->title") . '
          '; + ?> +
          +
          +
          + story->legendMailto;?> +
          mailto); foreach($mailto as $account) echo ' ' . $users[trim($account)]; ?>
          +
          +
          + story->legendVersion;?> +
          version; $i >= 1; $i --) echo html::a(inlink('view', "storyID=$story->id&version=$i"), "#$i");?>
          +
          +
          + diff --git a/module/task/control.php b/module/task/control.php index 433314bac3..51afc1a495 100644 --- a/module/task/control.php +++ b/module/task/control.php @@ -1,730 +1,730 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -class task extends control -{ - /** - * Construct function, load model of project and story modules. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('project'); - $this->loadModel('story'); - } - - /** - * Create a task. - * - * @param int $projectID - * @param int $storyID - * @access public - * @return void - */ - public function create($projectID = 0, $storyID = 0) - { - $project = $this->project->getById($projectID); - $taskLink = $this->createLink('project', 'browse', "projectID=$projectID&tab=task"); - $storyLink = $this->session->storyList ? $this->session->storyList : $this->createLink('project', 'story', "projectID=$projectID"); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - - /* Set menu. */ - $this->project->setMenu($this->project->getPairs(), $project->id); - - if(!empty($_POST)) - { - $tasksID = $this->task->create($projectID); - if(dao::isError()) die(js::error(dao::getError())); - - /* Create actions. */ - $this->loadModel('action'); - foreach($tasksID as $taskID) - { - $actionID = $this->action->create('task', $taskID, 'Opened', ''); - $this->sendmail($taskID, $actionID); - } - - /* Locate the browser. */ - if($this->post->after == 'continueAdding') - { - echo js::alert($this->lang->task->successSaved . $this->lang->task->afterChoices['continueAdding']); - die(js::locate($this->createLink('task', 'create', "projectID=$projectID&storyID={$this->post->story}"), 'parent')); - } - elseif($this->post->after == 'toTastList') - { - die(js::locate($taskLink, 'parent')); - } - elseif($this->post->after == 'toStoryList') - { - die(js::locate($storyLink, 'parent')); - } - } - - $stories = $this->story->getProjectStoryPairs($projectID); - $members = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); - $header['title'] = $project->name . $this->lang->colon . $this->lang->task->create; - $position[] = html::a($taskLink, $project->name); - $position[] = $this->lang->task->create; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->project = $project; - $this->view->stories = $stories; - $this->view->storyID = $storyID; - $this->view->members = $members; - $this->display(); - } - - /** - * Create a task. - * - * @param int $projectID - * @param int $storyID - * @access public - * @return void - */ - public function batchCreate($projectID = 0, $storyID = 0) - { - $project = $this->project->getById($projectID); - $taskLink = $this->createLink('project', 'browse', "projectID=$projectID&tab=task"); - $storyLink = $this->session->storyList ? $this->session->storyList : $this->createLink('project', 'story', "projectID=$projectID"); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - - /* Set menu. */ - $this->project->setMenu($this->project->getPairs(), $project->id); - - if(!empty($_POST)) - { - $mails = $this->task->batchCreate($projectID); - if(dao::isError()) die(js::error(dao::getError())); - - foreach($mails as $mail) - { - $this->sendmail($mail->taskID, $mail->actionID); - } - - /* Locate the browser. */ - die(js::locate($taskLink, 'parent')); - } - - $stories = $this->story->getProjectStoryPairs($projectID); - $stories['same'] = $this->lang->task->same; - $members = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); - $header['title'] = $project->name . $this->lang->colon . $this->lang->task->create; - $position[] = html::a($taskLink, $project->name); - $position[] = $this->lang->task->create; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->project = $project; - $this->view->stories = $stories; - $this->view->storyID = $storyID; - $this->view->members = $members; - $this->display(); - } - - /** - * Common actions of task module. - * - * @param int $taskID - * @access public - * @return void - */ - public function commonAction($taskID) - { - $this->view->task = $this->loadModel('task')->getByID($taskID); - $this->view->project = $this->project->getById($this->view->task->project); - $this->view->members = $this->project->getTeamMemberPairs($this->view->project->id ,'nodeleted'); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->actions = $this->loadModel('action')->getList('task', $taskID); - - /* Set menu. */ - $this->project->setMenu($this->project->getPairs(), $this->view->project->id); - $this->view->position[] = html::a($this->createLink('project', 'browse', "project={$this->view->task->project}"), $this->view->project->name); - - } - - /** - * Edit a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function edit($taskID, $comment = false) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = array(); - $files = array(); - if($comment == false) - { - $changes = $this->task->update($taskID); - if(dao::isError()) die(js::error(dao::getError())); - $files = $this->loadModel('file')->saveUpload('task', $taskID); - } - - $task = $this->task->getById($taskID); - if($this->post->comment != '' or !empty($changes) or !empty($files)) - { - $action = !empty($changes) ? 'Edited' : 'Commented'; - $fileAction = ''; - if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; - $actionID = $this->action->create('task', $taskID, $action, $fileAction . $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - - if($task->fromBug != 0) - { - foreach($changes as $change) - { - if($change['field'] == 'status') - { - $confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug"); - $cancelURL = $this->server->HTTP_REFERER; - die(js::confirm(sprintf($this->lang->task->remindBug, $task->fromBug), $confirmURL, $cancelURL, 'parent', 'parent')); - } - } - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->lang->task->edit; - $this->view->position[] = $this->lang->task->edit; - $this->view->stories = $this->story->getProjectStoryPairs($this->view->project->id); - $this->view->members = $this->loadModel('user')->appendDeleted($this->view->members, $this->view->task->assignedTo); - - $this->display(); - } - - /** - * Update assign of task - * - * @param int $requestID - * @access public - * @return void - */ - public function assignTo($projectID, $taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $actionID = $this->task->assign($taskID); - if(dao::isError()) die(js::error(dao::getError())); - $this->sendmail($taskID, $actionID); - - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon . $this->lang->task->assign; - $this->view->position[] = $this->lang->task->assign; - - $this->view->users = $this->project->getTeamMemberPairs($projectID); - $this->display(); - } - - /** - * View a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function view($taskID) - { - $task = $this->task->getById($taskID); - if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); - - /* Set menu. */ - $project = $this->project->getById($task->project); - $this->project->setMenu($this->project->getPairs(), $project->id); - - $header['title'] = $project->name . $this->lang->colon . $this->lang->task->view; - $position[] = html::a($this->createLink('project', 'browse', "projectID=$task->project"), $project->name); - $position[] = $this->lang->task->view; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->project = $project; - $this->view->task = $task; - $this->view->actions = $this->loadModel('action')->getList('task', $taskID); - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->display(); - } - - /** - * Confirm story change - * - * @param int $taskID - * @access public - * @return void - */ - public function confirmStoryChange($taskID) - { - $task = $this->task->getById($taskID); - $this->dao->update(TABLE_TASK)->set('storyVersion')->eq($task->latestStoryVersion)->where('id')->eq($taskID)->exec(); - $this->loadModel('action')->create('task', $taskID, 'confirmed', '', $task->latestStoryVersion); - die(js::reload('parent')); - } - - /** - * Start a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function start($taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = $this->task->start($taskID); - if(dao::isError()) die(js::error(dao::getError())); - - if($this->post->comment != '' or !empty($changes)) - { - $actionID = $this->action->create('task', $taskID, 'Started', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->start; - $this->view->position[] = $this->lang->task->start; - $this->display(); - } - - /** - * Finish a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function finish($taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = $this->task->finish($taskID); - if(dao::isError()) die(js::error(dao::getError())); - - $task = $this->task->getById($taskID); - if($this->post->comment != '' or !empty($changes)) - { - $actionID = $this->action->create('task', $taskID, 'Finished', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - - if($task->fromBug != 0) - { - foreach($changes as $change) - { - if($change['field'] == 'status') - { - $confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug"); - $cancelURL = $this->server->HTTP_REFERER; - die(js::confirm(sprintf($this->lang->task->remindBug, $task->fromBug), $confirmURL, $cancelURL, 'parent', 'parent')); - } - } - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->finish; - $this->view->position[] = $this->lang->task->finish; - - $this->display(); - } - - /** - * Close a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function close($taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = $this->task->close($taskID); - if(dao::isError()) die(js::error(dao::getError())); - - if($this->post->comment != '' or !empty($changes)) - { - $actionID = $this->action->create('task', $taskID, 'Closed', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->finish; - $this->view->position[] = $this->lang->task->finish; - - $this->display(); - - } - - /** - * Batch close tasks. - * - * @access public - * @return void - */ - public function batchClose() - { - if($this->post->tasks) - { - $tasks = $this->post->tasks; - unset($_POST['tasks']); - $this->loadModel('action'); - - foreach($tasks as $taskID) - { - $this->commonAction($taskID); - $task = $this->task->getById($taskID); - if($task->status == 'wait' or $task->status == 'doing') continue; - - $changes = $this->task->close($taskID); - - if($changes) - { - $actionID = $this->action->create('task', $taskID, 'Closed', ''); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - } - } - die(js::reload('parent')); - } - - /** - * Cancel a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function cancel($taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = $this->task->cancel($taskID); - if(dao::isError()) die(js::error(dao::getError())); - - if($this->post->comment != '' or !empty($changes)) - { - $actionID = $this->action->create('task', $taskID, 'Canceled', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->cancel; - $this->view->position[] = $this->lang->task->cancel; - - $this->display(); - } - - /** - * Activate a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function activate($taskID) - { - $this->commonAction($taskID); - - if(!empty($_POST)) - { - $this->loadModel('action'); - $changes = $this->task->activate($taskID); - if(dao::isError()) die(js::error(dao::getError())); - - if($this->post->comment != '' or !empty($changes)) - { - $actionID = $this->action->create('task', $taskID, 'Activated', $this->post->comment); - $this->action->logHistory($actionID, $changes); - $this->sendmail($taskID, $actionID); - } - die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); - } - - $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->activate; - $this->view->position[] = $this->lang->task->activate; - $this->display(); - } - - /** - * Delete a task. - * - * @param int $projectID - * @param int $taskID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($projectID, $taskID, $confirm = 'no') - { - $task = $this->task->getById($taskID); - if($confirm == 'no') - { - die(js::confirm($this->lang->task->confirmDelete, inlink('delete', "projectID=$projectID&taskID=$taskID&confirm=yes"))); - } - else - { - $story = $this->dao->select('story')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch('story'); - $this->task->delete(TABLE_TASK, $taskID); - if($task->fromBug != 0) $this->dao->update(TABLE_BUG)->set('toTask')->eq(0)->where('id')->eq($task->fromBug)->exec(); - if($story) $this->loadModel('story')->setStage($story); - die(js::locate($this->session->taskList, 'parent')); - } - } - - /** - * Send email. - * - * @param int $taskID - * @param int $actionID - * @access public - * @return void - */ - public function sendmail($taskID, $actionID) - { - /* Set toList and ccList. */ - $task = $this->task->getById($taskID); - $projectName = $this->project->getById($task->project)->name; - $toList = $task->assignedTo; - $ccList = trim($task->mailto, ','); - - if($toList == '') - { - if($ccList == '') return; - if(strpos($ccList, ',') === false) - { - $toList = $ccList; - $ccList = ''; - } - else - { - $commaPos = strpos($ccList, ','); - $toList = substr($ccList, 0, $commaPos); - $ccList = substr($ccList, $commaPos + 1); - } - } - elseif(strtolower($toList) == 'closed') - { - $toList = $task->finishedBy; - } - - /* Get action info. */ - $action = $this->loadModel('action')->getById($actionID); - $history = $this->action->getHistory($actionID); - $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); - - /* Create the email content. */ - $this->view->task = $task; - $this->view->action = $action; - $this->clear(); - $mailContent = $this->parse($this->moduleName, 'sendmail'); - - /* Send emails. */ - $this->loadModel('mail')->send($toList, $projectName . ':' . 'TASK#' . $task->id . $this->lang->colon . $task->name, $mailContent, $ccList); - if($this->mail->isError()) echo js::error($this->mail->getError()); - } - - /** - * AJAX: return tasks of a user in html select. - * - * @param string $account - * @param string $status - * @access public - * @return string - */ - public function ajaxGetUserTasks($account = '', $status = 'wait,doing') - { - if($account == '') $account = $this->app->user->account; - $tasks = $this->task->getUserTaskPairs($account, $status); - die(html::select('task', $tasks, '', 'class=select-1')); - } - - /** - * AJAX: return project tasks in html select. - * - * @param int $projectID - * @param int $taskID - * @access public - * @return string - */ - public function ajaxGetProjectTasks($projectID, $taskID = 0) - { - $tasks = $this->task->getProjectTaskPairs((int)$projectID); - die(html::select('task', $tasks, $taskID)); - } - - /** - * The report page. - * - * @param int $projectID - * @param string $browseType - * @access public - * @return void - */ - public function report($projectID, $browseType = 'all') - { - - $this->loadModel('report'); - $this->view->charts = array(); - $this->view->renderJS = ''; - - if(!empty($_POST)) - { - foreach($this->post->charts as $chart) - { - $chartFunc = 'getDataOf' . $chart; - $chartData = $this->task->$chartFunc(); - $chartOption = $this->lang->task->report->$chart; - $this->task->mergeChartOption($chart); - - $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); - $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); - $this->view->datas[$chart] = $this->report->computePercent($chartData); - } - $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); - } - - $this->project->setMenu($this->project->getPairs(), $projectID); - $this->projects = $this->project->getPairs(); - $this->view->header->title = $this->projects[$projectID] . $this->lang->colon . $this->lang->task->report->common; - $this->view->projectID = $projectID; - $this->view->browseType = $browseType; - $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; - - $this->display(); - } - - /** - * get data to export - * - * @param int $projectID - * @param string $orderBy - * @access public - * @return void - */ - public function export($projectID, $orderBy) - { - if($_POST) - { - $taskLang = $this->lang->task; - $taskConfig = $this->config->task; - - /* Create field lists. */ - $fields = explode(',', $taskConfig->exportFields); - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($taskLang->$fieldName) ? $taskLang->$fieldName : $fieldName; - unset($fields[$key]); - } - - /* Get tasks. */ - $tasks = $this->dao->select('*')->from(TABLE_TASK)->alias('t1')->where($this->session->taskReportCondition)->orderBy($orderBy)->fetchAll('id'); - - /* Get users and projects. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $projects = $this->loadModel('project')->getPairs('all'); - - /* Get related objects id lists. */ - $relatedStoryIdList = array(); - foreach($tasks as $task) $relatedStoryIdList[$task->story] = $task->story; - - /* Get related objects title or names. */ - $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('task')->andWhere('objectID')->in(@array_keys($tasks))->fetchGroup('objectID'); - - foreach($tasks as $task) - { - if($this->post->fileType == 'csv') - { - $task->desc = htmlspecialchars_decode($task->desc); - $task->desc = str_replace("
          ", "\n", $task->desc); - $task->desc = str_replace('"', '""', $task->desc); - } - - /* fill some field with useful value. */ - $task->story = isset($relatedStories[$task->story]) ? $relatedStories[$task->story] : ''; - - if(isset($projects[$task->project])) $task->project = $projects[$task->project]; - if(isset($taskLang->typeList[$task->type])) $task->type = $taskLang->typeList[$task->type]; - if(isset($taskLang->priList[$task->pri])) $task->pri = $taskLang->priList[$task->pri]; - if(isset($taskLang->statusList[$task->status])) $task->status = $taskLang->statusList[$task->status]; - if(isset($taskLang->reasonList[$task->closedReason])) $task->closedReason = $taskLang->reasonList[$task->closedReason]; - - if(isset($users[$task->openedBy])) $task->openedBy = $users[$task->openedBy]; - if(isset($users[$task->assignedTo])) $task->assignedTo = $users[$task->assignedTo]; - if(isset($users[$task->finishedBy])) $task->finishedBy = $users[$task->finishedBy]; - if(isset($users[$task->canceledBy])) $task->canceledBy = $users[$task->canceledBy]; - if(isset($users[$task->closedBy])) $task->closedBy = $users[$task->closedBy]; - if(isset($users[$task->lastEditedBy])) $task->lastEditedBy = $users[$task->lastEditedBy]; - - $task->openedDate = substr($task->openedDate, 0, 10); - $task->assignedDate = substr($task->assignedDate, 0, 10); - $task->finishedDate = substr($task->finishedDate, 0, 10); - $task->canceledDate = substr($task->canceledDate, 0, 10); - $task->closedDate = substr($task->closedDate, 0, 10); - $task->lastEditedDate = substr($task->lastEditedDate, 0, 10); - - /* Set related files. */ - if(isset($relatedFiles[$task->id])) - { - foreach($relatedFiles[$task->id] as $file) - { - $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$task->company/" . $file->pathname; - $task->files .= html::a($fileURL, $file->title, '_blank') . '
          '; - } - } - } - - $this->post->set('fields', $fields); - $this->post->set('rows', $tasks); - $this->fetch('file', 'export2' . $this->post->fileType, $_POST); - } - - $this->display(); - } -} + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +class task extends control +{ + /** + * Construct function, load model of project and story modules. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('project'); + $this->loadModel('story'); + } + + /** + * Create a task. + * + * @param int $projectID + * @param int $storyID + * @access public + * @return void + */ + public function create($projectID = 0, $storyID = 0) + { + $project = $this->project->getById($projectID); + $taskLink = $this->createLink('project', 'browse', "projectID=$projectID&tab=task"); + $storyLink = $this->session->storyList ? $this->session->storyList : $this->createLink('project', 'story', "projectID=$projectID"); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + /* Set menu. */ + $this->project->setMenu($this->project->getPairs(), $project->id); + + if(!empty($_POST)) + { + $tasksID = $this->task->create($projectID); + if(dao::isError()) die(js::error(dao::getError())); + + /* Create actions. */ + $this->loadModel('action'); + foreach($tasksID as $taskID) + { + $actionID = $this->action->create('task', $taskID, 'Opened', ''); + $this->sendmail($taskID, $actionID); + } + + /* Locate the browser. */ + if($this->post->after == 'continueAdding') + { + echo js::alert($this->lang->task->successSaved . $this->lang->task->afterChoices['continueAdding']); + die(js::locate($this->createLink('task', 'create', "projectID=$projectID&storyID={$this->post->story}"), 'parent')); + } + elseif($this->post->after == 'toTastList') + { + die(js::locate($taskLink, 'parent')); + } + elseif($this->post->after == 'toStoryList') + { + die(js::locate($storyLink, 'parent')); + } + } + + $stories = $this->story->getProjectStoryPairs($projectID); + $members = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); + $header['title'] = $project->name . $this->lang->colon . $this->lang->task->create; + $position[] = html::a($taskLink, $project->name); + $position[] = $this->lang->task->create; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->project = $project; + $this->view->stories = $stories; + $this->view->storyID = $storyID; + $this->view->members = $members; + $this->display(); + } + + /** + * Create a task. + * + * @param int $projectID + * @param int $storyID + * @access public + * @return void + */ + public function batchCreate($projectID = 0, $storyID = 0) + { + $project = $this->project->getById($projectID); + $taskLink = $this->createLink('project', 'browse', "projectID=$projectID&tab=task"); + $storyLink = $this->session->storyList ? $this->session->storyList : $this->createLink('project', 'story', "projectID=$projectID"); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + /* Set menu. */ + $this->project->setMenu($this->project->getPairs(), $project->id); + + if(!empty($_POST)) + { + $mails = $this->task->batchCreate($projectID); + if(dao::isError()) die(js::error(dao::getError())); + + foreach($mails as $mail) + { + $this->sendmail($mail->taskID, $mail->actionID); + } + + /* Locate the browser. */ + die(js::locate($taskLink, 'parent')); + } + + $stories = $this->story->getProjectStoryPairs($projectID); + $stories['same'] = $this->lang->task->same; + $members = $this->project->getTeamMemberPairs($projectID, 'nodeleted'); + $header['title'] = $project->name . $this->lang->colon . $this->lang->task->create; + $position[] = html::a($taskLink, $project->name); + $position[] = $this->lang->task->create; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->project = $project; + $this->view->stories = $stories; + $this->view->storyID = $storyID; + $this->view->members = $members; + $this->display(); + } + + /** + * Common actions of task module. + * + * @param int $taskID + * @access public + * @return void + */ + public function commonAction($taskID) + { + $this->view->task = $this->loadModel('task')->getByID($taskID); + $this->view->project = $this->project->getById($this->view->task->project); + $this->view->members = $this->project->getTeamMemberPairs($this->view->project->id ,'nodeleted'); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->actions = $this->loadModel('action')->getList('task', $taskID); + + /* Set menu. */ + $this->project->setMenu($this->project->getPairs(), $this->view->project->id); + $this->view->position[] = html::a($this->createLink('project', 'browse', "project={$this->view->task->project}"), $this->view->project->name); + + } + + /** + * Edit a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function edit($taskID, $comment = false) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = array(); + $files = array(); + if($comment == false) + { + $changes = $this->task->update($taskID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('task', $taskID); + } + + $task = $this->task->getById($taskID); + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $action = !empty($changes) ? 'Edited' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n" ; + $actionID = $this->action->create('task', $taskID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + + if($task->fromBug != 0) + { + foreach($changes as $change) + { + if($change['field'] == 'status') + { + $confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug"); + $cancelURL = $this->server->HTTP_REFERER; + die(js::confirm(sprintf($this->lang->task->remindBug, $task->fromBug), $confirmURL, $cancelURL, 'parent', 'parent')); + } + } + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->lang->task->edit; + $this->view->position[] = $this->lang->task->edit; + $this->view->stories = $this->story->getProjectStoryPairs($this->view->project->id); + $this->view->members = $this->loadModel('user')->appendDeleted($this->view->members, $this->view->task->assignedTo); + + $this->display(); + } + + /** + * Update assign of task + * + * @param int $requestID + * @access public + * @return void + */ + public function assignTo($projectID, $taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $actionID = $this->task->assign($taskID); + if(dao::isError()) die(js::error(dao::getError())); + $this->sendmail($taskID, $actionID); + + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon . $this->lang->task->assign; + $this->view->position[] = $this->lang->task->assign; + + $this->view->users = $this->project->getTeamMemberPairs($projectID); + $this->display(); + } + + /** + * View a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function view($taskID) + { + $task = $this->task->getById($taskID); + if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); + + /* Set menu. */ + $project = $this->project->getById($task->project); + $this->project->setMenu($this->project->getPairs(), $project->id); + + $header['title'] = $project->name . $this->lang->colon . $this->lang->task->view; + $position[] = html::a($this->createLink('project', 'browse', "projectID=$task->project"), $project->name); + $position[] = $this->lang->task->view; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->project = $project; + $this->view->task = $task; + $this->view->actions = $this->loadModel('action')->getList('task', $taskID); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->display(); + } + + /** + * Confirm story change + * + * @param int $taskID + * @access public + * @return void + */ + public function confirmStoryChange($taskID) + { + $task = $this->task->getById($taskID); + $this->dao->update(TABLE_TASK)->set('storyVersion')->eq($task->latestStoryVersion)->where('id')->eq($taskID)->exec(); + $this->loadModel('action')->create('task', $taskID, 'confirmed', '', $task->latestStoryVersion); + die(js::reload('parent')); + } + + /** + * Start a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function start($taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = $this->task->start($taskID); + if(dao::isError()) die(js::error(dao::getError())); + + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('task', $taskID, 'Started', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->start; + $this->view->position[] = $this->lang->task->start; + $this->display(); + } + + /** + * Finish a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function finish($taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = $this->task->finish($taskID); + if(dao::isError()) die(js::error(dao::getError())); + + $task = $this->task->getById($taskID); + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('task', $taskID, 'Finished', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + + if($task->fromBug != 0) + { + foreach($changes as $change) + { + if($change['field'] == 'status') + { + $confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug"); + $cancelURL = $this->server->HTTP_REFERER; + die(js::confirm(sprintf($this->lang->task->remindBug, $task->fromBug), $confirmURL, $cancelURL, 'parent', 'parent')); + } + } + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->finish; + $this->view->position[] = $this->lang->task->finish; + + $this->display(); + } + + /** + * Close a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function close($taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = $this->task->close($taskID); + if(dao::isError()) die(js::error(dao::getError())); + + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('task', $taskID, 'Closed', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->finish; + $this->view->position[] = $this->lang->task->finish; + + $this->display(); + + } + + /** + * Batch close tasks. + * + * @access public + * @return void + */ + public function batchClose() + { + if($this->post->tasks) + { + $tasks = $this->post->tasks; + unset($_POST['tasks']); + $this->loadModel('action'); + + foreach($tasks as $taskID) + { + $this->commonAction($taskID); + $task = $this->task->getById($taskID); + if($task->status == 'wait' or $task->status == 'doing') continue; + + $changes = $this->task->close($taskID); + + if($changes) + { + $actionID = $this->action->create('task', $taskID, 'Closed', ''); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + } + } + die(js::reload('parent')); + } + + /** + * Cancel a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function cancel($taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = $this->task->cancel($taskID); + if(dao::isError()) die(js::error(dao::getError())); + + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('task', $taskID, 'Canceled', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->cancel; + $this->view->position[] = $this->lang->task->cancel; + + $this->display(); + } + + /** + * Activate a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function activate($taskID) + { + $this->commonAction($taskID); + + if(!empty($_POST)) + { + $this->loadModel('action'); + $changes = $this->task->activate($taskID); + if(dao::isError()) die(js::error(dao::getError())); + + if($this->post->comment != '' or !empty($changes)) + { + $actionID = $this->action->create('task', $taskID, 'Activated', $this->post->comment); + $this->action->logHistory($actionID, $changes); + $this->sendmail($taskID, $actionID); + } + die(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); + } + + $this->view->header->title = $this->view->project->name . $this->lang->colon .$this->lang->task->activate; + $this->view->position[] = $this->lang->task->activate; + $this->display(); + } + + /** + * Delete a task. + * + * @param int $projectID + * @param int $taskID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($projectID, $taskID, $confirm = 'no') + { + $task = $this->task->getById($taskID); + if($confirm == 'no') + { + die(js::confirm($this->lang->task->confirmDelete, inlink('delete', "projectID=$projectID&taskID=$taskID&confirm=yes"))); + } + else + { + $story = $this->dao->select('story')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch('story'); + $this->task->delete(TABLE_TASK, $taskID); + if($task->fromBug != 0) $this->dao->update(TABLE_BUG)->set('toTask')->eq(0)->where('id')->eq($task->fromBug)->exec(); + if($story) $this->loadModel('story')->setStage($story); + die(js::locate($this->session->taskList, 'parent')); + } + } + + /** + * Send email. + * + * @param int $taskID + * @param int $actionID + * @access public + * @return void + */ + public function sendmail($taskID, $actionID) + { + /* Set toList and ccList. */ + $task = $this->task->getById($taskID); + $projectName = $this->project->getById($task->project)->name; + $toList = $task->assignedTo; + $ccList = trim($task->mailto, ','); + + if($toList == '') + { + if($ccList == '') return; + if(strpos($ccList, ',') === false) + { + $toList = $ccList; + $ccList = ''; + } + else + { + $commaPos = strpos($ccList, ','); + $toList = substr($ccList, 0, $commaPos); + $ccList = substr($ccList, $commaPos + 1); + } + } + elseif(strtolower($toList) == 'closed') + { + $toList = $task->finishedBy; + } + + /* Get action info. */ + $action = $this->loadModel('action')->getById($actionID); + $history = $this->action->getHistory($actionID); + $action->history = isset($history[$actionID]) ? $history[$actionID] : array(); + + /* Create the email content. */ + $this->view->task = $task; + $this->view->action = $action; + $this->clear(); + $mailContent = $this->parse($this->moduleName, 'sendmail'); + + /* Send emails. */ + $this->loadModel('mail')->send($toList, $projectName . ':' . 'TASK#' . $task->id . $this->lang->colon . $task->name, $mailContent, $ccList); + if($this->mail->isError()) echo js::error($this->mail->getError()); + } + + /** + * AJAX: return tasks of a user in html select. + * + * @param string $account + * @param string $status + * @access public + * @return string + */ + public function ajaxGetUserTasks($account = '', $status = 'wait,doing') + { + if($account == '') $account = $this->app->user->account; + $tasks = $this->task->getUserTaskPairs($account, $status); + die(html::select('task', $tasks, '', 'class=select-1')); + } + + /** + * AJAX: return project tasks in html select. + * + * @param int $projectID + * @param int $taskID + * @access public + * @return string + */ + public function ajaxGetProjectTasks($projectID, $taskID = 0) + { + $tasks = $this->task->getProjectTaskPairs((int)$projectID); + die(html::select('task', $tasks, $taskID)); + } + + /** + * The report page. + * + * @param int $projectID + * @param string $browseType + * @access public + * @return void + */ + public function report($projectID, $browseType = 'all') + { + + $this->loadModel('report'); + $this->view->charts = array(); + $this->view->renderJS = ''; + + if(!empty($_POST)) + { + foreach($this->post->charts as $chart) + { + $chartFunc = 'getDataOf' . $chart; + $chartData = $this->task->$chartFunc(); + $chartOption = $this->lang->task->report->$chart; + $this->task->mergeChartOption($chart); + + $chartXML = $this->report->createSingleXML($chartData, $chartOption->graph); + $this->view->charts[$chart] = $this->report->createJSChart($chartOption->swf, $chartXML, $chartOption->width, $chartOption->height); + $this->view->datas[$chart] = $this->report->computePercent($chartData); + } + $this->view->renderJS = $this->report->renderJsCharts(count($this->view->charts)); + } + + $this->project->setMenu($this->project->getPairs(), $projectID); + $this->projects = $this->project->getPairs(); + $this->view->header->title = $this->projects[$projectID] . $this->lang->colon . $this->lang->task->report->common; + $this->view->projectID = $projectID; + $this->view->browseType = $browseType; + $this->view->checkedCharts = $this->post->charts ? join(',', $this->post->charts) : ''; + + $this->display(); + } + + /** + * get data to export + * + * @param int $projectID + * @param string $orderBy + * @access public + * @return void + */ + public function export($projectID, $orderBy) + { + if($_POST) + { + $taskLang = $this->lang->task; + $taskConfig = $this->config->task; + + /* Create field lists. */ + $fields = explode(',', $taskConfig->exportFields); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($taskLang->$fieldName) ? $taskLang->$fieldName : $fieldName; + unset($fields[$key]); + } + + /* Get tasks. */ + $tasks = $this->dao->select('*')->from(TABLE_TASK)->alias('t1')->where($this->session->taskReportCondition)->orderBy($orderBy)->fetchAll('id'); + + /* Get users and projects. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $projects = $this->loadModel('project')->getPairs('all'); + + /* Get related objects id lists. */ + $relatedStoryIdList = array(); + foreach($tasks as $task) $relatedStoryIdList[$task->story] = $task->story; + + /* Get related objects title or names. */ + $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedFiles = $this->dao->select('id, objectID, pathname, title')->from(TABLE_FILE)->where('objectType')->eq('task')->andWhere('objectID')->in(@array_keys($tasks))->fetchGroup('objectID'); + + foreach($tasks as $task) + { + if($this->post->fileType == 'csv') + { + $task->desc = htmlspecialchars_decode($task->desc); + $task->desc = str_replace("
          ", "\n", $task->desc); + $task->desc = str_replace('"', '""', $task->desc); + } + + /* fill some field with useful value. */ + $task->story = isset($relatedStories[$task->story]) ? $relatedStories[$task->story] : ''; + + if(isset($projects[$task->project])) $task->project = $projects[$task->project]; + if(isset($taskLang->typeList[$task->type])) $task->type = $taskLang->typeList[$task->type]; + if(isset($taskLang->priList[$task->pri])) $task->pri = $taskLang->priList[$task->pri]; + if(isset($taskLang->statusList[$task->status])) $task->status = $taskLang->statusList[$task->status]; + if(isset($taskLang->reasonList[$task->closedReason])) $task->closedReason = $taskLang->reasonList[$task->closedReason]; + + if(isset($users[$task->openedBy])) $task->openedBy = $users[$task->openedBy]; + if(isset($users[$task->assignedTo])) $task->assignedTo = $users[$task->assignedTo]; + if(isset($users[$task->finishedBy])) $task->finishedBy = $users[$task->finishedBy]; + if(isset($users[$task->canceledBy])) $task->canceledBy = $users[$task->canceledBy]; + if(isset($users[$task->closedBy])) $task->closedBy = $users[$task->closedBy]; + if(isset($users[$task->lastEditedBy])) $task->lastEditedBy = $users[$task->lastEditedBy]; + + $task->openedDate = substr($task->openedDate, 0, 10); + $task->assignedDate = substr($task->assignedDate, 0, 10); + $task->finishedDate = substr($task->finishedDate, 0, 10); + $task->canceledDate = substr($task->canceledDate, 0, 10); + $task->closedDate = substr($task->closedDate, 0, 10); + $task->lastEditedDate = substr($task->lastEditedDate, 0, 10); + + /* Set related files. */ + if(isset($relatedFiles[$task->id])) + { + foreach($relatedFiles[$task->id] as $file) + { + $fileURL = 'http://' . $this->server->http_host . $this->config->webRoot . "data/upload/$task->company/" . $file->pathname; + $task->files .= html::a($fileURL, $file->title, '_blank') . '
          '; + } + } + } + + $this->post->set('fields', $fields); + $this->post->set('rows', $tasks); + $this->fetch('file', 'export2' . $this->post->fileType, $_POST); + } + + $this->display(); + } +} diff --git a/module/task/lang/en.php b/module/task/lang/en.php index c1877c452e..59a3be548f 100644 --- a/module/task/lang/en.php +++ b/module/task/lang/en.php @@ -1,179 +1,179 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->task->index = "Index"; -$lang->task->create = "Create"; -$lang->task->batchCreate = "Batch create"; -$lang->task->import = "Import undone"; -$lang->task->edit = "Update"; -$lang->task->delete = "Delete"; -$lang->task->view = "Info"; -$lang->task->logEfforts = "Efforts"; -$lang->task->start = "Start"; -$lang->task->finish = "Finish"; -$lang->task->close = "Close"; -$lang->task->batchClose = "Batch close"; -$lang->task->cancel = "Cancel"; -$lang->task->activate = "Activate"; -$lang->task->export = "Export"; -$lang->task->reportChart = "Report chart"; -$lang->task->fromBug = 'From Bug'; -$lang->task->confirmStoryChange = "Confirm story change"; - -$lang->task->common = 'Task'; -$lang->task->id = 'ID'; -$lang->task->project = 'Project'; -$lang->task->story = 'Story'; -$lang->task->storyVersion = 'Version'; -$lang->task->name = 'Name'; -$lang->task->type = 'Type'; -$lang->task->pri = 'Pri'; -$lang->task->mailto = 'Mailto'; -$lang->task->estimate = 'Estimate'; -$lang->task->estimateAB = 'Est'; -$lang->task->left = 'Left'; -$lang->task->leftAB = 'Left'; -$lang->task->consumed = 'Consumed'; -$lang->task->consumedAB = 'Use'; -$lang->task->deadline = 'Deadline'; -$lang->task->deadlineAB = 'Deadline'; -$lang->task->status = 'Status'; -$lang->task->statusCustom = 'Status Order'; -$lang->task->desc = 'Desc'; -$lang->task->assign = 'Assign'; -$lang->task->assignedTo = 'Assigned To'; -$lang->task->assignedToAB = 'Assign'; -$lang->task->assignedDate = 'Assigned Date'; -$lang->task->openedBy = 'Opened By'; -$lang->task->openedByAB = 'Open'; -$lang->task->openedDate = 'Opened Date'; -$lang->task->openedDateAB = 'Open'; -$lang->task->finishedBy = 'Finished By'; -$lang->task->finishedByAB = 'Finishe'; -$lang->task->finishedDate = 'Finished Date'; -$lang->task->finishedDateAB = 'Date'; -$lang->task->canceledBy = 'Canceled By'; -$lang->task->canceledDate = 'Canceled Date'; -$lang->task->closedBy = 'Closed By'; -$lang->task->closedDate = 'Closed Date'; -$lang->task->closedReason = 'Closed Reason'; -$lang->task->lastEditedBy = 'Last Edited By'; -$lang->task->lastEditedDate = 'Last Edited Date'; -$lang->task->lastEdited = 'Last Edited'; - -$lang->task->same = 'The same as above'; -$lang->task->notes = '(Notes: the name, type, pri and estimate must be written, otherwise it is no use)'; - -$lang->task->statusList[''] = ''; -$lang->task->statusList['wait'] = 'Pending'; -$lang->task->statusList['doing'] = 'In progress'; -$lang->task->statusList['done'] = 'Done'; -$lang->task->statusList['cancel'] = 'Canceled'; -$lang->task->statusList['closed'] = 'Closed'; - -$lang->task->typeList[''] = ''; -$lang->task->typeList['design'] = 'Design'; -$lang->task->typeList['devel'] = 'Devel'; -$lang->task->typeList['test'] = 'Test'; -$lang->task->typeList['study'] = 'Study'; -$lang->task->typeList['discuss'] = 'Discuss'; -$lang->task->typeList['ui'] = 'UI'; -$lang->task->typeList['affair'] = 'Affair'; -$lang->task->typeList['misc'] = 'Misc'; - -$lang->task->priList[0] = ''; -$lang->task->priList[3] = '3'; -$lang->task->priList[1] = '1'; -$lang->task->priList[2] = '2'; -$lang->task->priList[4] = '4'; - -$lang->task->reasonList[''] = ''; -$lang->task->reasonList['done'] = 'Done'; -$lang->task->reasonList['cancel'] = 'Canceled'; - -$lang->task->afterChoices['continueAdding'] = 'Continue to add task for this story. '; -$lang->task->afterChoices['toTastList'] = 'To task list. '; -$lang->task->afterChoices['toStoryList'] = 'To story list. '; - -$lang->task->buttonEdit = 'Edit'; -$lang->task->buttonClose = 'Close'; -$lang->task->buttonCancel = 'Cancel'; -$lang->task->buttonActivate = 'Activate'; -$lang->task->buttonLogEfforts = 'Efforts'; -$lang->task->buttonDelete = 'Delete'; -$lang->task->buttonBackToList = 'Back'; -$lang->task->buttonStart = 'Start'; -$lang->task->buttonDone = 'Done'; - -$lang->task->legendBasic = 'Basic info'; -$lang->task->legendEffort = 'Effort'; -$lang->task->legendLife = 'Lifetime'; -$lang->task->legendDesc = 'Desc'; -$lang->task->legendAction = 'Action'; - -$lang->task->ajaxGetUserTasks = "API:My tasks"; -$lang->task->ajaxGetProjectTasks = "API:Project tasks"; -$lang->task->confirmDelete = "Are you sure you want to delete this task?"; -$lang->task->copyStoryTitle = "Same as story"; -$lang->task->afterSubmit = "After created"; -$lang->task->successSaved = "Successfully saved"; -$lang->task->delayWarning = " Postponed %s days "; -$lang->task->remindBug = "This task from Bug, update the Bug:%s or not?"; - -/* Report. */ -$lang->task->report->common = 'Report'; -$lang->task->report->select = 'Select'; -$lang->task->report->create = 'Create'; -$lang->task->report->selectAll = 'All'; -$lang->task->report->selectReverse = 'Reverse'; - -$lang->task->report->charts['tasksPerProject'] = 'Project tasks'; -$lang->task->report->charts['tasksPerAssignedTo'] = 'Assigned To'; -$lang->task->report->charts['tasksPerType'] = 'Type'; -$lang->task->report->charts['tasksPerPri'] = 'Priority'; -$lang->task->report->charts['tasksPerStatus'] = 'Status'; -$lang->task->report->charts['tasksPerDeadline'] = 'Deadline'; -$lang->task->report->charts['tasksPerEstimate'] = 'Estimate time'; -$lang->task->report->charts['tasksPerLeft'] = 'Left time'; -$lang->task->report->charts['tasksPerConsumed'] = 'Consumed time'; -$lang->task->report->charts['tasksPerFinishedBy'] = 'Finished By'; -$lang->task->report->charts['tasksPerClosedReason'] = 'Closed reason'; -$lang->task->report->charts['finishedTasksPerDay'] = 'Finished tasks per day'; - -$lang->task->report->options->swf = 'pie2d'; -$lang->task->report->options->width = 'auto'; -$lang->task->report->options->height = 300; -$lang->task->report->options->graph->baseFontSize = 12; -$lang->task->report->options->graph->showNames = 1; -$lang->task->report->options->graph->formatNumber = 1; -$lang->task->report->options->graph->decimalPrecision = 0; -$lang->task->report->options->graph->animation = 0; -$lang->task->report->options->graph->rotateNames = 0; -$lang->task->report->options->graph->yAxisName = 'COUNT'; -$lang->task->report->options->graph->pieRadius = 100; -$lang->task->report->options->graph->showColumnShadow = 0; - -$lang->task->report->tasksPerProject->graph->xAxisName = 'Project'; -$lang->task->report->tasksPerAssignedTo->graph->xAxisName = 'User'; -$lang->task->report->tasksPerType->graph->xAxisName = 'Type'; -$lang->task->report->tasksPerPri->graph->xAxisName = 'Pri'; -$lang->task->report->tasksPerStatus->graph->xAxisName = 'Status'; -$lang->task->report->tasksPerDeadline->graph->xAxisName = 'Date'; -$lang->task->report->tasksPerEstimate->graph->xAxisName = 'Time'; -$lang->task->report->tasksPerLeft->graph->xAxisName = 'Time'; -$lang->task->report->tasksPerConsumed->graph->xAxisName = 'Time'; -$lang->task->report->tasksPerFinishedBy->graph->xAxisName = 'User'; -$lang->task->report->tasksPerClosedReason->graph->xAxisName = 'Closed Reason'; - -$lang->task->report->finishedTasksPerDay->swf = 'column2d'; -$lang->task->report->finishedTasksPerDay->height = 400; -$lang->task->report->finishedTasksPerDay->graph->xAxisName = 'Date'; -$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->task->index = "Index"; +$lang->task->create = "Create"; +$lang->task->batchCreate = "Batch create"; +$lang->task->import = "Import undone"; +$lang->task->edit = "Update"; +$lang->task->delete = "Delete"; +$lang->task->view = "Info"; +$lang->task->logEfforts = "Efforts"; +$lang->task->start = "Start"; +$lang->task->finish = "Finish"; +$lang->task->close = "Close"; +$lang->task->batchClose = "Batch close"; +$lang->task->cancel = "Cancel"; +$lang->task->activate = "Activate"; +$lang->task->export = "Export"; +$lang->task->reportChart = "Report chart"; +$lang->task->fromBug = 'From Bug'; +$lang->task->confirmStoryChange = "Confirm story change"; + +$lang->task->common = 'Task'; +$lang->task->id = 'ID'; +$lang->task->project = 'Project'; +$lang->task->story = 'Story'; +$lang->task->storyVersion = 'Version'; +$lang->task->name = 'Name'; +$lang->task->type = 'Type'; +$lang->task->pri = 'Pri'; +$lang->task->mailto = 'Mailto'; +$lang->task->estimate = 'Estimate'; +$lang->task->estimateAB = 'Est'; +$lang->task->left = 'Left'; +$lang->task->leftAB = 'Left'; +$lang->task->consumed = 'Consumed'; +$lang->task->consumedAB = 'Use'; +$lang->task->deadline = 'Deadline'; +$lang->task->deadlineAB = 'Deadline'; +$lang->task->status = 'Status'; +$lang->task->statusCustom = 'Status Order'; +$lang->task->desc = 'Desc'; +$lang->task->assign = 'Assign'; +$lang->task->assignedTo = 'Assigned To'; +$lang->task->assignedToAB = 'Assign'; +$lang->task->assignedDate = 'Assigned Date'; +$lang->task->openedBy = 'Opened By'; +$lang->task->openedByAB = 'Open'; +$lang->task->openedDate = 'Opened Date'; +$lang->task->openedDateAB = 'Open'; +$lang->task->finishedBy = 'Finished By'; +$lang->task->finishedByAB = 'Finishe'; +$lang->task->finishedDate = 'Finished Date'; +$lang->task->finishedDateAB = 'Date'; +$lang->task->canceledBy = 'Canceled By'; +$lang->task->canceledDate = 'Canceled Date'; +$lang->task->closedBy = 'Closed By'; +$lang->task->closedDate = 'Closed Date'; +$lang->task->closedReason = 'Closed Reason'; +$lang->task->lastEditedBy = 'Last Edited By'; +$lang->task->lastEditedDate = 'Last Edited Date'; +$lang->task->lastEdited = 'Last Edited'; + +$lang->task->same = 'The same as above'; +$lang->task->notes = '(Notes: the name, type, pri and estimate must be written, otherwise it is no use)'; + +$lang->task->statusList[''] = ''; +$lang->task->statusList['wait'] = 'Pending'; +$lang->task->statusList['doing'] = 'In progress'; +$lang->task->statusList['done'] = 'Done'; +$lang->task->statusList['cancel'] = 'Canceled'; +$lang->task->statusList['closed'] = 'Closed'; + +$lang->task->typeList[''] = ''; +$lang->task->typeList['design'] = 'Design'; +$lang->task->typeList['devel'] = 'Devel'; +$lang->task->typeList['test'] = 'Test'; +$lang->task->typeList['study'] = 'Study'; +$lang->task->typeList['discuss'] = 'Discuss'; +$lang->task->typeList['ui'] = 'UI'; +$lang->task->typeList['affair'] = 'Affair'; +$lang->task->typeList['misc'] = 'Misc'; + +$lang->task->priList[0] = ''; +$lang->task->priList[3] = '3'; +$lang->task->priList[1] = '1'; +$lang->task->priList[2] = '2'; +$lang->task->priList[4] = '4'; + +$lang->task->reasonList[''] = ''; +$lang->task->reasonList['done'] = 'Done'; +$lang->task->reasonList['cancel'] = 'Canceled'; + +$lang->task->afterChoices['continueAdding'] = 'Continue to add task for this story. '; +$lang->task->afterChoices['toTastList'] = 'To task list. '; +$lang->task->afterChoices['toStoryList'] = 'To story list. '; + +$lang->task->buttonEdit = 'Edit'; +$lang->task->buttonClose = 'Close'; +$lang->task->buttonCancel = 'Cancel'; +$lang->task->buttonActivate = 'Activate'; +$lang->task->buttonLogEfforts = 'Efforts'; +$lang->task->buttonDelete = 'Delete'; +$lang->task->buttonBackToList = 'Back'; +$lang->task->buttonStart = 'Start'; +$lang->task->buttonDone = 'Done'; + +$lang->task->legendBasic = 'Basic info'; +$lang->task->legendEffort = 'Effort'; +$lang->task->legendLife = 'Lifetime'; +$lang->task->legendDesc = 'Desc'; +$lang->task->legendAction = 'Action'; + +$lang->task->ajaxGetUserTasks = "API:My tasks"; +$lang->task->ajaxGetProjectTasks = "API:Project tasks"; +$lang->task->confirmDelete = "Are you sure you want to delete this task?"; +$lang->task->copyStoryTitle = "Same as story"; +$lang->task->afterSubmit = "After created"; +$lang->task->successSaved = "Successfully saved"; +$lang->task->delayWarning = " Postponed %s days "; +$lang->task->remindBug = "This task from Bug, update the Bug:%s or not?"; + +/* Report. */ +$lang->task->report->common = 'Report'; +$lang->task->report->select = 'Select'; +$lang->task->report->create = 'Create'; +$lang->task->report->selectAll = 'All'; +$lang->task->report->selectReverse = 'Reverse'; + +$lang->task->report->charts['tasksPerProject'] = 'Project tasks'; +$lang->task->report->charts['tasksPerAssignedTo'] = 'Assigned To'; +$lang->task->report->charts['tasksPerType'] = 'Type'; +$lang->task->report->charts['tasksPerPri'] = 'Priority'; +$lang->task->report->charts['tasksPerStatus'] = 'Status'; +$lang->task->report->charts['tasksPerDeadline'] = 'Deadline'; +$lang->task->report->charts['tasksPerEstimate'] = 'Estimate time'; +$lang->task->report->charts['tasksPerLeft'] = 'Left time'; +$lang->task->report->charts['tasksPerConsumed'] = 'Consumed time'; +$lang->task->report->charts['tasksPerFinishedBy'] = 'Finished By'; +$lang->task->report->charts['tasksPerClosedReason'] = 'Closed reason'; +$lang->task->report->charts['finishedTasksPerDay'] = 'Finished tasks per day'; + +$lang->task->report->options->swf = 'pie2d'; +$lang->task->report->options->width = 'auto'; +$lang->task->report->options->height = 300; +$lang->task->report->options->graph->baseFontSize = 12; +$lang->task->report->options->graph->showNames = 1; +$lang->task->report->options->graph->formatNumber = 1; +$lang->task->report->options->graph->decimalPrecision = 0; +$lang->task->report->options->graph->animation = 0; +$lang->task->report->options->graph->rotateNames = 0; +$lang->task->report->options->graph->yAxisName = 'COUNT'; +$lang->task->report->options->graph->pieRadius = 100; +$lang->task->report->options->graph->showColumnShadow = 0; + +$lang->task->report->tasksPerProject->graph->xAxisName = 'Project'; +$lang->task->report->tasksPerAssignedTo->graph->xAxisName = 'User'; +$lang->task->report->tasksPerType->graph->xAxisName = 'Type'; +$lang->task->report->tasksPerPri->graph->xAxisName = 'Pri'; +$lang->task->report->tasksPerStatus->graph->xAxisName = 'Status'; +$lang->task->report->tasksPerDeadline->graph->xAxisName = 'Date'; +$lang->task->report->tasksPerEstimate->graph->xAxisName = 'Time'; +$lang->task->report->tasksPerLeft->graph->xAxisName = 'Time'; +$lang->task->report->tasksPerConsumed->graph->xAxisName = 'Time'; +$lang->task->report->tasksPerFinishedBy->graph->xAxisName = 'User'; +$lang->task->report->tasksPerClosedReason->graph->xAxisName = 'Closed Reason'; + +$lang->task->report->finishedTasksPerDay->swf = 'column2d'; +$lang->task->report->finishedTasksPerDay->height = 400; +$lang->task->report->finishedTasksPerDay->graph->xAxisName = 'Date'; +$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; diff --git a/module/task/lang/zh-cn.php b/module/task/lang/zh-cn.php index 8aba9a896a..20cb2bd6b1 100644 --- a/module/task/lang/zh-cn.php +++ b/module/task/lang/zh-cn.php @@ -1,179 +1,179 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->task->index = "任务一览"; -$lang->task->create = "新增任务"; -$lang->task->batchCreate = "批量添加"; -$lang->task->import = "导入之前未完任务"; -$lang->task->edit = "编辑任务"; -$lang->task->delete = "删除任务"; -$lang->task->view = "查看任务"; -$lang->task->logEfforts = "记录工时"; -$lang->task->start = "开始任务"; -$lang->task->finish = "完成任务"; -$lang->task->close = "关闭任务"; -$lang->task->batchClose = "批量关闭"; -$lang->task->cancel = "取消任务"; -$lang->task->activate = "激活任务"; -$lang->task->export = "导出数据"; -$lang->task->reportChart = "报表统计"; -$lang->task->fromBug = '来源Bug'; -$lang->task->confirmStoryChange = "确认需求变动"; - -$lang->task->common = '任务'; -$lang->task->id = '编号'; -$lang->task->project = '所属项目'; -$lang->task->story = '相关需求'; -$lang->task->storyVersion = '需求版本'; -$lang->task->name = '任务名称'; -$lang->task->type = '任务类型'; -$lang->task->pri = '优先级'; -$lang->task->mailto = '抄送给'; -$lang->task->estimate = '最初预计'; -$lang->task->estimateAB = '预'; -$lang->task->left = '预计剩余'; -$lang->task->leftAB = '剩'; -$lang->task->consumed = '已经消耗'; -$lang->task->consumedAB = '耗'; -$lang->task->deadline = '截止日期'; -$lang->task->deadlineAB = '截止'; -$lang->task->status = '任务状态'; -$lang->task->statusCustom = '状态排序'; -$lang->task->desc = '任务描述'; -$lang->task->assign = '指派'; -$lang->task->assignedTo = '指派给'; -$lang->task->assignedToAB = '指派给'; -$lang->task->assignedDate = '指派日期'; -$lang->task->openedBy = '由谁创建'; -$lang->task->openedByAB = '创建者'; -$lang->task->openedDate = '创建日期'; -$lang->task->openedDateAB = '创建'; -$lang->task->finishedBy = '由谁完成'; -$lang->task->finishedByAB = '完成者'; -$lang->task->finishedDate = '完成时间'; -$lang->task->finishedDateAB = '完成'; -$lang->task->canceledBy = '由谁取消'; -$lang->task->canceledDate = '取消时间'; -$lang->task->closedBy = '由谁关闭'; -$lang->task->closedDate = '关闭时间'; -$lang->task->closedReason = '关闭原因'; -$lang->task->lastEditedBy = '最后修改'; -$lang->task->lastEditedDate = '最后修改日期'; -$lang->task->lastEdited = '最后编辑'; - -$lang->task->same = '同上'; -$lang->task->notes = '(注:“任务类型”、“任务名称”、“优先级”和“预计工时”必需填写,否则此行无效)'; - -$lang->task->statusList[''] = ''; -$lang->task->statusList['wait'] = '未开始'; -$lang->task->statusList['doing'] = '进行中'; -$lang->task->statusList['done'] = '已完成'; -$lang->task->statusList['cancel'] = '已取消'; -$lang->task->statusList['closed'] = '已关闭'; - -$lang->task->typeList[''] = ''; -$lang->task->typeList['design'] = '设计'; -$lang->task->typeList['devel'] = '开发'; -$lang->task->typeList['test'] = '测试'; -$lang->task->typeList['study'] = '研究'; -$lang->task->typeList['discuss'] = '讨论'; -$lang->task->typeList['ui'] = '界面'; -$lang->task->typeList['affair'] = '事务'; -$lang->task->typeList['misc'] = '其他'; - -$lang->task->priList[0] = ''; -$lang->task->priList[3] = '3'; -$lang->task->priList[1] = '1'; -$lang->task->priList[2] = '2'; -$lang->task->priList[4] = '4'; - -$lang->task->reasonList[''] = ''; -$lang->task->reasonList['done'] = '已完成'; -$lang->task->reasonList['cancel'] = '已取消'; - -$lang->task->afterChoices['continueAdding'] = '继续为该需求添加任务'; -$lang->task->afterChoices['toTastList'] = '返回任务列表'; -$lang->task->afterChoices['toStoryList'] = '返回需求列表'; - -$lang->task->buttonEdit = '编辑'; -$lang->task->buttonClose = '关闭'; -$lang->task->buttonCancel = '取消'; -$lang->task->buttonActivate = '激活'; -$lang->task->buttonLogEfforts = '记录工时'; -$lang->task->buttonDelete = '删除'; -$lang->task->buttonBackToList = '返回'; -$lang->task->buttonStart = '开始'; -$lang->task->buttonDone = '完成'; - -$lang->task->legendBasic = '基本信息'; -$lang->task->legendEffort = '工时信息'; -$lang->task->legendLife = '任务的一生'; -$lang->task->legendDesc = '任务描述'; -$lang->task->legendAction = '操作'; - -$lang->task->ajaxGetUserTasks = "接口:我的任务"; -$lang->task->ajaxGetProjectTasks = "接口:项目任务"; -$lang->task->confirmDelete = "您确定要删除这个任务吗?"; -$lang->task->copyStoryTitle = "同需求"; -$lang->task->afterSubmit = "添加之后"; -$lang->task->successSaved = "成功添加,"; -$lang->task->delayWarning = " 延期%s天 "; -$lang->task->remindBug = "该任务为Bug转化得到,是否更新Bug:%s ?"; - -/* 统计报表。*/ -$lang->task->report->common = '统计报表'; -$lang->task->report->select = '请选择报表类型'; -$lang->task->report->create = '生成报表'; -$lang->task->report->selectAll = '全选'; -$lang->task->report->selectReverse = '反选'; - -$lang->task->report->charts['tasksPerProject'] = '项目任务数统计'; -$lang->task->report->charts['tasksPerAssignedTo'] = '指派给统计'; -$lang->task->report->charts['tasksPerType'] = '任务类型统计'; -$lang->task->report->charts['tasksPerPri'] = '优先级统计'; -$lang->task->report->charts['tasksPerStatus'] = '任务状态统计'; -$lang->task->report->charts['tasksPerDeadline'] = '截止日期统计'; -$lang->task->report->charts['tasksPerEstimate'] = '预计时间统计'; -$lang->task->report->charts['tasksPerLeft'] = '剩余时间统计'; -$lang->task->report->charts['tasksPerConsumed'] = '消耗时间统计'; -$lang->task->report->charts['tasksPerFinishedBy'] = '由谁完成统计'; -$lang->task->report->charts['tasksPerClosedReason'] = '关闭原因统计'; -$lang->task->report->charts['finishedTasksPerDay'] = '每天完成统计'; - -$lang->task->report->options->swf = 'pie2d'; -$lang->task->report->options->width = 'auto'; -$lang->task->report->options->height = 300; -$lang->task->report->options->graph->baseFontSize = 12; -$lang->task->report->options->graph->showNames = 1; -$lang->task->report->options->graph->formatNumber = 1; -$lang->task->report->options->graph->decimalPrecision = 0; -$lang->task->report->options->graph->animation = 0; -$lang->task->report->options->graph->rotateNames = 0; -$lang->task->report->options->graph->yAxisName = 'COUNT'; -$lang->task->report->options->graph->pieRadius = 100; // 饼图直径。 -$lang->task->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 - -$lang->task->report->tasksPerProject->graph->xAxisName = '项目'; -$lang->task->report->tasksPerAssignedTo->graph->xAxisName = '用户'; -$lang->task->report->tasksPerType->graph->xAxisName = '类型'; -$lang->task->report->tasksPerPri->graph->xAxisName = '优先级'; -$lang->task->report->tasksPerStatus->graph->xAxisName = '状态'; -$lang->task->report->tasksPerDeadline->graph->xAxisName = '日期'; -$lang->task->report->tasksPerEstimate->graph->xAxisName = '时间'; -$lang->task->report->tasksPerLeft->graph->xAxisName = '时间'; -$lang->task->report->tasksPerConsumed->graph->xAxisName = '时间'; -$lang->task->report->tasksPerFinishedBy->graph->xAxisName = '用户'; -$lang->task->report->tasksPerClosedReason->graph->xAxisName = '关闭原因'; - -$lang->task->report->finishedTasksPerDay->swf = 'column2d'; -$lang->task->report->finishedTasksPerDay->height = 400; -$lang->task->report->finishedTasksPerDay->graph->xAxisName = '日期'; -$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->task->index = "任务一览"; +$lang->task->create = "新增任务"; +$lang->task->batchCreate = "批量添加"; +$lang->task->import = "导入之前未完任务"; +$lang->task->edit = "编辑任务"; +$lang->task->delete = "删除任务"; +$lang->task->view = "查看任务"; +$lang->task->logEfforts = "记录工时"; +$lang->task->start = "开始任务"; +$lang->task->finish = "完成任务"; +$lang->task->close = "关闭任务"; +$lang->task->batchClose = "批量关闭"; +$lang->task->cancel = "取消任务"; +$lang->task->activate = "激活任务"; +$lang->task->export = "导出数据"; +$lang->task->reportChart = "报表统计"; +$lang->task->fromBug = '来源Bug'; +$lang->task->confirmStoryChange = "确认需求变动"; + +$lang->task->common = '任务'; +$lang->task->id = '编号'; +$lang->task->project = '所属项目'; +$lang->task->story = '相关需求'; +$lang->task->storyVersion = '需求版本'; +$lang->task->name = '任务名称'; +$lang->task->type = '任务类型'; +$lang->task->pri = '优先级'; +$lang->task->mailto = '抄送给'; +$lang->task->estimate = '最初预计'; +$lang->task->estimateAB = '预'; +$lang->task->left = '预计剩余'; +$lang->task->leftAB = '剩'; +$lang->task->consumed = '已经消耗'; +$lang->task->consumedAB = '耗'; +$lang->task->deadline = '截止日期'; +$lang->task->deadlineAB = '截止'; +$lang->task->status = '任务状态'; +$lang->task->statusCustom = '状态排序'; +$lang->task->desc = '任务描述'; +$lang->task->assign = '指派'; +$lang->task->assignedTo = '指派给'; +$lang->task->assignedToAB = '指派给'; +$lang->task->assignedDate = '指派日期'; +$lang->task->openedBy = '由谁创建'; +$lang->task->openedByAB = '创建者'; +$lang->task->openedDate = '创建日期'; +$lang->task->openedDateAB = '创建'; +$lang->task->finishedBy = '由谁完成'; +$lang->task->finishedByAB = '完成者'; +$lang->task->finishedDate = '完成时间'; +$lang->task->finishedDateAB = '完成'; +$lang->task->canceledBy = '由谁取消'; +$lang->task->canceledDate = '取消时间'; +$lang->task->closedBy = '由谁关闭'; +$lang->task->closedDate = '关闭时间'; +$lang->task->closedReason = '关闭原因'; +$lang->task->lastEditedBy = '最后修改'; +$lang->task->lastEditedDate = '最后修改日期'; +$lang->task->lastEdited = '最后编辑'; + +$lang->task->same = '同上'; +$lang->task->notes = '(注:“任务类型”、“任务名称”、“优先级”和“预计工时”必需填写,否则此行无效)'; + +$lang->task->statusList[''] = ''; +$lang->task->statusList['wait'] = '未开始'; +$lang->task->statusList['doing'] = '进行中'; +$lang->task->statusList['done'] = '已完成'; +$lang->task->statusList['cancel'] = '已取消'; +$lang->task->statusList['closed'] = '已关闭'; + +$lang->task->typeList[''] = ''; +$lang->task->typeList['design'] = '设计'; +$lang->task->typeList['devel'] = '开发'; +$lang->task->typeList['test'] = '测试'; +$lang->task->typeList['study'] = '研究'; +$lang->task->typeList['discuss'] = '讨论'; +$lang->task->typeList['ui'] = '界面'; +$lang->task->typeList['affair'] = '事务'; +$lang->task->typeList['misc'] = '其他'; + +$lang->task->priList[0] = ''; +$lang->task->priList[3] = '3'; +$lang->task->priList[1] = '1'; +$lang->task->priList[2] = '2'; +$lang->task->priList[4] = '4'; + +$lang->task->reasonList[''] = ''; +$lang->task->reasonList['done'] = '已完成'; +$lang->task->reasonList['cancel'] = '已取消'; + +$lang->task->afterChoices['continueAdding'] = '继续为该需求添加任务'; +$lang->task->afterChoices['toTastList'] = '返回任务列表'; +$lang->task->afterChoices['toStoryList'] = '返回需求列表'; + +$lang->task->buttonEdit = '编辑'; +$lang->task->buttonClose = '关闭'; +$lang->task->buttonCancel = '取消'; +$lang->task->buttonActivate = '激活'; +$lang->task->buttonLogEfforts = '记录工时'; +$lang->task->buttonDelete = '删除'; +$lang->task->buttonBackToList = '返回'; +$lang->task->buttonStart = '开始'; +$lang->task->buttonDone = '完成'; + +$lang->task->legendBasic = '基本信息'; +$lang->task->legendEffort = '工时信息'; +$lang->task->legendLife = '任务的一生'; +$lang->task->legendDesc = '任务描述'; +$lang->task->legendAction = '操作'; + +$lang->task->ajaxGetUserTasks = "接口:我的任务"; +$lang->task->ajaxGetProjectTasks = "接口:项目任务"; +$lang->task->confirmDelete = "您确定要删除这个任务吗?"; +$lang->task->copyStoryTitle = "同需求"; +$lang->task->afterSubmit = "添加之后"; +$lang->task->successSaved = "成功添加,"; +$lang->task->delayWarning = " 延期%s天 "; +$lang->task->remindBug = "该任务为Bug转化得到,是否更新Bug:%s ?"; + +/* 统计报表。*/ +$lang->task->report->common = '统计报表'; +$lang->task->report->select = '请选择报表类型'; +$lang->task->report->create = '生成报表'; +$lang->task->report->selectAll = '全选'; +$lang->task->report->selectReverse = '反选'; + +$lang->task->report->charts['tasksPerProject'] = '项目任务数统计'; +$lang->task->report->charts['tasksPerAssignedTo'] = '指派给统计'; +$lang->task->report->charts['tasksPerType'] = '任务类型统计'; +$lang->task->report->charts['tasksPerPri'] = '优先级统计'; +$lang->task->report->charts['tasksPerStatus'] = '任务状态统计'; +$lang->task->report->charts['tasksPerDeadline'] = '截止日期统计'; +$lang->task->report->charts['tasksPerEstimate'] = '预计时间统计'; +$lang->task->report->charts['tasksPerLeft'] = '剩余时间统计'; +$lang->task->report->charts['tasksPerConsumed'] = '消耗时间统计'; +$lang->task->report->charts['tasksPerFinishedBy'] = '由谁完成统计'; +$lang->task->report->charts['tasksPerClosedReason'] = '关闭原因统计'; +$lang->task->report->charts['finishedTasksPerDay'] = '每天完成统计'; + +$lang->task->report->options->swf = 'pie2d'; +$lang->task->report->options->width = 'auto'; +$lang->task->report->options->height = 300; +$lang->task->report->options->graph->baseFontSize = 12; +$lang->task->report->options->graph->showNames = 1; +$lang->task->report->options->graph->formatNumber = 1; +$lang->task->report->options->graph->decimalPrecision = 0; +$lang->task->report->options->graph->animation = 0; +$lang->task->report->options->graph->rotateNames = 0; +$lang->task->report->options->graph->yAxisName = 'COUNT'; +$lang->task->report->options->graph->pieRadius = 100; // 饼图直径。 +$lang->task->report->options->graph->showColumnShadow = 0; // 是否显示柱状图阴影。 + +$lang->task->report->tasksPerProject->graph->xAxisName = '项目'; +$lang->task->report->tasksPerAssignedTo->graph->xAxisName = '用户'; +$lang->task->report->tasksPerType->graph->xAxisName = '类型'; +$lang->task->report->tasksPerPri->graph->xAxisName = '优先级'; +$lang->task->report->tasksPerStatus->graph->xAxisName = '状态'; +$lang->task->report->tasksPerDeadline->graph->xAxisName = '日期'; +$lang->task->report->tasksPerEstimate->graph->xAxisName = '时间'; +$lang->task->report->tasksPerLeft->graph->xAxisName = '时间'; +$lang->task->report->tasksPerConsumed->graph->xAxisName = '时间'; +$lang->task->report->tasksPerFinishedBy->graph->xAxisName = '用户'; +$lang->task->report->tasksPerClosedReason->graph->xAxisName = '关闭原因'; + +$lang->task->report->finishedTasksPerDay->swf = 'column2d'; +$lang->task->report->finishedTasksPerDay->height = 400; +$lang->task->report->finishedTasksPerDay->graph->xAxisName = '日期'; +$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; diff --git a/module/task/lang/zh-tw.php b/module/task/lang/zh-tw.php index 2ba7dbfdd7..aeebee057e 100644 --- a/module/task/lang/zh-tw.php +++ b/module/task/lang/zh-tw.php @@ -1,179 +1,179 @@ - - * @package task - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->task->index = "任務一覽"; -$lang->task->create = "新增任務"; -$lang->task->batchCreate = "批量添加"; -$lang->task->import = "導入之前未完任務"; -$lang->task->edit = "編輯任務"; -$lang->task->delete = "刪除任務"; -$lang->task->view = "查看任務"; -$lang->task->logEfforts = "記錄工時"; -$lang->task->start = "開始任務"; -$lang->task->finish = "完成任務"; -$lang->task->close = "關閉任務"; -$lang->task->batchClose = "批量關閉"; -$lang->task->cancel = "取消任務"; -$lang->task->activate = "激活任務"; -$lang->task->export = "導出數據"; -$lang->task->reportChart = "報表統計"; -$lang->task->fromBug = '來源Bug'; -$lang->task->confirmStoryChange = "確認需求變動"; - -$lang->task->common = '任務'; -$lang->task->id = '編號'; -$lang->task->project = '所屬項目'; -$lang->task->story = '相關需求'; -$lang->task->storyVersion = '需求版本'; -$lang->task->name = '任務名稱'; -$lang->task->type = '任務類型'; -$lang->task->pri = '優先順序'; -$lang->task->mailto = '抄送給'; -$lang->task->estimate = '最初預計'; -$lang->task->estimateAB = '預'; -$lang->task->left = '預計剩餘'; -$lang->task->leftAB = '剩'; -$lang->task->consumed = '已經消耗'; -$lang->task->consumedAB = '耗'; -$lang->task->deadline = '截止日期'; -$lang->task->deadlineAB = '截止'; -$lang->task->status = '任務狀態'; -$lang->task->statusCustom = '狀態排序'; -$lang->task->desc = '任務描述'; -$lang->task->assign = '指派'; -$lang->task->assignedTo = '指派給'; -$lang->task->assignedToAB = '指派給'; -$lang->task->assignedDate = '指派日期'; -$lang->task->openedBy = '由誰創建'; -$lang->task->openedByAB = '創建者'; -$lang->task->openedDate = '創建日期'; -$lang->task->openedDateAB = '創建'; -$lang->task->finishedBy = '由誰完成'; -$lang->task->finishedByAB = '完成者'; -$lang->task->finishedDate = '完成時間'; -$lang->task->finishedDateAB = '完成'; -$lang->task->canceledBy = '由誰取消'; -$lang->task->canceledDate = '取消時間'; -$lang->task->closedBy = '由誰關閉'; -$lang->task->closedDate = '關閉時間'; -$lang->task->closedReason = '關閉原因'; -$lang->task->lastEditedBy = '最後修改'; -$lang->task->lastEditedDate = '最後修改日期'; -$lang->task->lastEdited = '最後編輯'; - -$lang->task->same = '同上'; -$lang->task->notes = '(註:“任務類型”、“任務名稱”、“優先順序”和“預計工時”必需填寫,否則此行無效)'; - -$lang->task->statusList[''] = ''; -$lang->task->statusList['wait'] = '未開始'; -$lang->task->statusList['doing'] = '進行中'; -$lang->task->statusList['done'] = '已完成'; -$lang->task->statusList['cancel'] = '已取消'; -$lang->task->statusList['closed'] = '已關閉'; - -$lang->task->typeList[''] = ''; -$lang->task->typeList['design'] = '設計'; -$lang->task->typeList['devel'] = '開發'; -$lang->task->typeList['test'] = '測試'; -$lang->task->typeList['study'] = '研究'; -$lang->task->typeList['discuss'] = '討論'; -$lang->task->typeList['ui'] = '界面'; -$lang->task->typeList['affair'] = '事務'; -$lang->task->typeList['misc'] = '其他'; - -$lang->task->priList[0] = ''; -$lang->task->priList[3] = '3'; -$lang->task->priList[1] = '1'; -$lang->task->priList[2] = '2'; -$lang->task->priList[4] = '4'; - -$lang->task->reasonList[''] = ''; -$lang->task->reasonList['done'] = '已完成'; -$lang->task->reasonList['cancel'] = '已取消'; - -$lang->task->afterChoices['continueAdding'] = '繼續為該需求添加任務'; -$lang->task->afterChoices['toTastList'] = '返回任務列表'; -$lang->task->afterChoices['toStoryList'] = '返回需求列表'; - -$lang->task->buttonEdit = '編輯'; -$lang->task->buttonClose = '關閉'; -$lang->task->buttonCancel = '取消'; -$lang->task->buttonActivate = '激活'; -$lang->task->buttonLogEfforts = '記錄工時'; -$lang->task->buttonDelete = '刪除'; -$lang->task->buttonBackToList = '返回'; -$lang->task->buttonStart = '開始'; -$lang->task->buttonDone = '完成'; - -$lang->task->legendBasic = '基本信息'; -$lang->task->legendEffort = '工時信息'; -$lang->task->legendLife = '任務的一生'; -$lang->task->legendDesc = '任務描述'; -$lang->task->legendAction = '操作'; - -$lang->task->ajaxGetUserTasks = "介面:我的任務"; -$lang->task->ajaxGetProjectTasks = "介面:項目任務"; -$lang->task->confirmDelete = "您確定要刪除這個任務嗎?"; -$lang->task->copyStoryTitle = "同需求"; -$lang->task->afterSubmit = "添加之後"; -$lang->task->successSaved = "成功添加,"; -$lang->task->delayWarning = " 延期%s天 "; -$lang->task->remindBug = "該任務為Bug轉化得到,是否更新Bug:%s ?"; - -/* 統計報表。*/ -$lang->task->report->common = '統計報表'; -$lang->task->report->select = '請選擇報表類型'; -$lang->task->report->create = '生成報表'; -$lang->task->report->selectAll = '全選'; -$lang->task->report->selectReverse = '反選'; - -$lang->task->report->charts['tasksPerProject'] = '項目任務數統計'; -$lang->task->report->charts['tasksPerAssignedTo'] = '指派給統計'; -$lang->task->report->charts['tasksPerType'] = '任務類型統計'; -$lang->task->report->charts['tasksPerPri'] = '優先順序統計'; -$lang->task->report->charts['tasksPerStatus'] = '任務狀態統計'; -$lang->task->report->charts['tasksPerDeadline'] = '截止日期統計'; -$lang->task->report->charts['tasksPerEstimate'] = '預計時間統計'; -$lang->task->report->charts['tasksPerLeft'] = '剩餘時間統計'; -$lang->task->report->charts['tasksPerConsumed'] = '消耗時間統計'; -$lang->task->report->charts['tasksPerFinishedBy'] = '由誰完成統計'; -$lang->task->report->charts['tasksPerClosedReason'] = '關閉原因統計'; -$lang->task->report->charts['finishedTasksPerDay'] = '每天完成統計'; - -$lang->task->report->options->swf = 'pie2d'; -$lang->task->report->options->width = 'auto'; -$lang->task->report->options->height = 300; -$lang->task->report->options->graph->baseFontSize = 12; -$lang->task->report->options->graph->showNames = 1; -$lang->task->report->options->graph->formatNumber = 1; -$lang->task->report->options->graph->decimalPrecision = 0; -$lang->task->report->options->graph->animation = 0; -$lang->task->report->options->graph->rotateNames = 0; -$lang->task->report->options->graph->yAxisName = 'COUNT'; -$lang->task->report->options->graph->pieRadius = 100; // 餅圖直徑。 -$lang->task->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 - -$lang->task->report->tasksPerProject->graph->xAxisName = '項目'; -$lang->task->report->tasksPerAssignedTo->graph->xAxisName = '用戶'; -$lang->task->report->tasksPerType->graph->xAxisName = '類型'; -$lang->task->report->tasksPerPri->graph->xAxisName = '優先順序'; -$lang->task->report->tasksPerStatus->graph->xAxisName = '狀態'; -$lang->task->report->tasksPerDeadline->graph->xAxisName = '日期'; -$lang->task->report->tasksPerEstimate->graph->xAxisName = '時間'; -$lang->task->report->tasksPerLeft->graph->xAxisName = '時間'; -$lang->task->report->tasksPerConsumed->graph->xAxisName = '時間'; -$lang->task->report->tasksPerFinishedBy->graph->xAxisName = '用戶'; -$lang->task->report->tasksPerClosedReason->graph->xAxisName = '關閉原因'; - -$lang->task->report->finishedTasksPerDay->swf = 'column2d'; -$lang->task->report->finishedTasksPerDay->height = 400; -$lang->task->report->finishedTasksPerDay->graph->xAxisName = '日期'; -$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; + + * @package task + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->task->index = "任務一覽"; +$lang->task->create = "新增任務"; +$lang->task->batchCreate = "批量添加"; +$lang->task->import = "導入之前未完任務"; +$lang->task->edit = "編輯任務"; +$lang->task->delete = "刪除任務"; +$lang->task->view = "查看任務"; +$lang->task->logEfforts = "記錄工時"; +$lang->task->start = "開始任務"; +$lang->task->finish = "完成任務"; +$lang->task->close = "關閉任務"; +$lang->task->batchClose = "批量關閉"; +$lang->task->cancel = "取消任務"; +$lang->task->activate = "激活任務"; +$lang->task->export = "導出數據"; +$lang->task->reportChart = "報表統計"; +$lang->task->fromBug = '來源Bug'; +$lang->task->confirmStoryChange = "確認需求變動"; + +$lang->task->common = '任務'; +$lang->task->id = '編號'; +$lang->task->project = '所屬項目'; +$lang->task->story = '相關需求'; +$lang->task->storyVersion = '需求版本'; +$lang->task->name = '任務名稱'; +$lang->task->type = '任務類型'; +$lang->task->pri = '優先順序'; +$lang->task->mailto = '抄送給'; +$lang->task->estimate = '最初預計'; +$lang->task->estimateAB = '預'; +$lang->task->left = '預計剩餘'; +$lang->task->leftAB = '剩'; +$lang->task->consumed = '已經消耗'; +$lang->task->consumedAB = '耗'; +$lang->task->deadline = '截止日期'; +$lang->task->deadlineAB = '截止'; +$lang->task->status = '任務狀態'; +$lang->task->statusCustom = '狀態排序'; +$lang->task->desc = '任務描述'; +$lang->task->assign = '指派'; +$lang->task->assignedTo = '指派給'; +$lang->task->assignedToAB = '指派給'; +$lang->task->assignedDate = '指派日期'; +$lang->task->openedBy = '由誰創建'; +$lang->task->openedByAB = '創建者'; +$lang->task->openedDate = '創建日期'; +$lang->task->openedDateAB = '創建'; +$lang->task->finishedBy = '由誰完成'; +$lang->task->finishedByAB = '完成者'; +$lang->task->finishedDate = '完成時間'; +$lang->task->finishedDateAB = '完成'; +$lang->task->canceledBy = '由誰取消'; +$lang->task->canceledDate = '取消時間'; +$lang->task->closedBy = '由誰關閉'; +$lang->task->closedDate = '關閉時間'; +$lang->task->closedReason = '關閉原因'; +$lang->task->lastEditedBy = '最後修改'; +$lang->task->lastEditedDate = '最後修改日期'; +$lang->task->lastEdited = '最後編輯'; + +$lang->task->same = '同上'; +$lang->task->notes = '(註:“任務類型”、“任務名稱”、“優先順序”和“預計工時”必需填寫,否則此行無效)'; + +$lang->task->statusList[''] = ''; +$lang->task->statusList['wait'] = '未開始'; +$lang->task->statusList['doing'] = '進行中'; +$lang->task->statusList['done'] = '已完成'; +$lang->task->statusList['cancel'] = '已取消'; +$lang->task->statusList['closed'] = '已關閉'; + +$lang->task->typeList[''] = ''; +$lang->task->typeList['design'] = '設計'; +$lang->task->typeList['devel'] = '開發'; +$lang->task->typeList['test'] = '測試'; +$lang->task->typeList['study'] = '研究'; +$lang->task->typeList['discuss'] = '討論'; +$lang->task->typeList['ui'] = '界面'; +$lang->task->typeList['affair'] = '事務'; +$lang->task->typeList['misc'] = '其他'; + +$lang->task->priList[0] = ''; +$lang->task->priList[3] = '3'; +$lang->task->priList[1] = '1'; +$lang->task->priList[2] = '2'; +$lang->task->priList[4] = '4'; + +$lang->task->reasonList[''] = ''; +$lang->task->reasonList['done'] = '已完成'; +$lang->task->reasonList['cancel'] = '已取消'; + +$lang->task->afterChoices['continueAdding'] = '繼續為該需求添加任務'; +$lang->task->afterChoices['toTastList'] = '返回任務列表'; +$lang->task->afterChoices['toStoryList'] = '返回需求列表'; + +$lang->task->buttonEdit = '編輯'; +$lang->task->buttonClose = '關閉'; +$lang->task->buttonCancel = '取消'; +$lang->task->buttonActivate = '激活'; +$lang->task->buttonLogEfforts = '記錄工時'; +$lang->task->buttonDelete = '刪除'; +$lang->task->buttonBackToList = '返回'; +$lang->task->buttonStart = '開始'; +$lang->task->buttonDone = '完成'; + +$lang->task->legendBasic = '基本信息'; +$lang->task->legendEffort = '工時信息'; +$lang->task->legendLife = '任務的一生'; +$lang->task->legendDesc = '任務描述'; +$lang->task->legendAction = '操作'; + +$lang->task->ajaxGetUserTasks = "介面:我的任務"; +$lang->task->ajaxGetProjectTasks = "介面:項目任務"; +$lang->task->confirmDelete = "您確定要刪除這個任務嗎?"; +$lang->task->copyStoryTitle = "同需求"; +$lang->task->afterSubmit = "添加之後"; +$lang->task->successSaved = "成功添加,"; +$lang->task->delayWarning = " 延期%s天 "; +$lang->task->remindBug = "該任務為Bug轉化得到,是否更新Bug:%s ?"; + +/* 統計報表。*/ +$lang->task->report->common = '統計報表'; +$lang->task->report->select = '請選擇報表類型'; +$lang->task->report->create = '生成報表'; +$lang->task->report->selectAll = '全選'; +$lang->task->report->selectReverse = '反選'; + +$lang->task->report->charts['tasksPerProject'] = '項目任務數統計'; +$lang->task->report->charts['tasksPerAssignedTo'] = '指派給統計'; +$lang->task->report->charts['tasksPerType'] = '任務類型統計'; +$lang->task->report->charts['tasksPerPri'] = '優先順序統計'; +$lang->task->report->charts['tasksPerStatus'] = '任務狀態統計'; +$lang->task->report->charts['tasksPerDeadline'] = '截止日期統計'; +$lang->task->report->charts['tasksPerEstimate'] = '預計時間統計'; +$lang->task->report->charts['tasksPerLeft'] = '剩餘時間統計'; +$lang->task->report->charts['tasksPerConsumed'] = '消耗時間統計'; +$lang->task->report->charts['tasksPerFinishedBy'] = '由誰完成統計'; +$lang->task->report->charts['tasksPerClosedReason'] = '關閉原因統計'; +$lang->task->report->charts['finishedTasksPerDay'] = '每天完成統計'; + +$lang->task->report->options->swf = 'pie2d'; +$lang->task->report->options->width = 'auto'; +$lang->task->report->options->height = 300; +$lang->task->report->options->graph->baseFontSize = 12; +$lang->task->report->options->graph->showNames = 1; +$lang->task->report->options->graph->formatNumber = 1; +$lang->task->report->options->graph->decimalPrecision = 0; +$lang->task->report->options->graph->animation = 0; +$lang->task->report->options->graph->rotateNames = 0; +$lang->task->report->options->graph->yAxisName = 'COUNT'; +$lang->task->report->options->graph->pieRadius = 100; // 餅圖直徑。 +$lang->task->report->options->graph->showColumnShadow = 0; // 是否顯示柱狀圖陰影。 + +$lang->task->report->tasksPerProject->graph->xAxisName = '項目'; +$lang->task->report->tasksPerAssignedTo->graph->xAxisName = '用戶'; +$lang->task->report->tasksPerType->graph->xAxisName = '類型'; +$lang->task->report->tasksPerPri->graph->xAxisName = '優先順序'; +$lang->task->report->tasksPerStatus->graph->xAxisName = '狀態'; +$lang->task->report->tasksPerDeadline->graph->xAxisName = '日期'; +$lang->task->report->tasksPerEstimate->graph->xAxisName = '時間'; +$lang->task->report->tasksPerLeft->graph->xAxisName = '時間'; +$lang->task->report->tasksPerConsumed->graph->xAxisName = '時間'; +$lang->task->report->tasksPerFinishedBy->graph->xAxisName = '用戶'; +$lang->task->report->tasksPerClosedReason->graph->xAxisName = '關閉原因'; + +$lang->task->report->finishedTasksPerDay->swf = 'column2d'; +$lang->task->report->finishedTasksPerDay->height = 400; +$lang->task->report->finishedTasksPerDay->graph->xAxisName = '日期'; +$lang->task->report->finishedTasksPerDay->graph->rotateNames = '1'; diff --git a/module/task/model.php b/module/task/model.php index 803e8eef04..65fece18b3 100644 --- a/module/task/model.php +++ b/module/task/model.php @@ -1,900 +1,900 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> -post->assignedTo as $assignedTo) - { - $task = fixer::input('post') - ->striptags('name') - ->add('project', (int)$projectID) - ->setDefault('estimate, left, story', 0) - ->setDefault('deadline', '0000-00-00') - ->setDefault('status', 'wait') - ->setIF($this->post->estimate != false, 'left', $this->post->estimate) - ->setForce('assignedTo', $assignedTo) - ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->setDefault('openedBy', $this->app->user->account) - ->setDefault('openedDate', helper::now()) - ->remove('after,files,labels') - ->get(); - - if($assignedTo) $task->assignedDate = helper::now(); - - $this->setStatus($task); - - $this->dao->insert(TABLE_TASK)->data($task) - ->autoCheck() - ->batchCheck($this->config->task->create->requiredFields, 'notempty') - ->checkIF($task->estimate != '', 'estimate', 'float') - ->exec(); - - if(!dao::isError()) - { - $taskID = $this->dao->lastInsertID(); - if($this->post->story) $this->loadModel('story')->setStage($this->post->story); - if(!empty($taskFile)) - { - $taskFile->objectID = $taskID; - $this->dao->insert(TABLE_FILE)->data($taskFile)->exec(); - } - else - { - $taskFileTitle = $this->loadModel('file')->saveUpload('task', $taskID); - $taskFile = $this->dao->select('*')->from(TABLE_FILE)->where('id')->eq(key($taskFileTitle))->fetch(); - unset($taskFile->id); - } - $tasksID[$assignedTo] = $taskID; - } - else - { - return false; - } - } - return $tasksID; - } - - /** - * Create a batch task. - * - * @param int $projectID - * @access public - * @return void - */ - public function batchCreate($projectID) - { - $now = helper::now(); - $tasks = fixer::input('post')->get(); - for($i = 0; $i < $this->config->task->batchCreate; $i++) - { - if($tasks->type[$i] != '' and $tasks->name[$i] != '' and $tasks->pri[$i] != 0 and $tasks->estimate[$i] != '') - { - $data[$i]->story = $tasks->story[$i] != 'same' ? $tasks->story[$i] : ($i == 0 ? 0 : $data[$i-1]->story); - $data[$i]->type = $tasks->type[$i] == 'same' ? ($i == 0 ? '' : $data[$i-1]->type) : $tasks->type[$i]; - $data[$i]->name = $tasks->name[$i]; - $data[$i]->desc = $tasks->desc[$i]; - $data[$i]->assignedTo = $tasks->assignedTo[$i]; - $data[$i]->pri = $tasks->pri[$i]; - $data[$i]->estimate = $tasks->estimate[$i]; - $data[$i]->left = $tasks->estimate[$i]; - $data[$i]->project = $projectID; - $data[$i]->deadline = '0000-00-00'; - $data[$i]->status = 'wait'; - $data[$i]->openedBy = $this->app->user->account; - $data[$i]->openedDate = $now; - $data[$i]->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, 'wait') + 1; - if($tasks->story[$i] != '') $data[$i]->storyVersion = $this->loadModel('story')->getVersion($data[$i]->story); - if($tasks->assignedTo[$i] != '') $data[$i]->assignedDate = $now; - - $this->dao->insert(TABLE_TASK)->data($data[$i]) - ->autoCheck() - ->batchCheck($this->config->task->create->requiredFields, 'notempty') - ->checkIF($data[$i]->estimate != '', 'estimate', 'float') - ->exec(); - - if(dao::isError()) - { - echo js::error(dao::getError()); - die(js::reload('parent')); - } - - $taskID = $this->dao->lastInsertID(); - if($tasks->story[$i] != false) $this->story->setStage($tasks->story[$i]); - $actionID = $this->loadModel('action')->create('task', $taskID, 'Opened', ''); - $mails[$i]->taskID = $taskID; - $mails[$i]->actionID = $actionID; - } - else - { - unset($tasks->story[$i]); - unset($tasks->type[$i]); - unset($tasks->name[$i]); - unset($tasks->desc[$i]); - unset($tasks->assignedTo[$i]); - unset($tasks->pri[$i]); - unset($tasks->estimate[$i]); - } - } - return $mails; - } - - /** - * Update a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function update($taskID) - { - $oldTask = $this->getById($taskID); - $now = helper::now(); - $task = fixer::input('post') - ->striptags('name') - ->setDefault('story, estimate, left, consumed', 0) - ->setDefault('deadline', '0000-00-00') - ->setIF($this->post->story != false and $this->post->story != $oldTask->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - - ->setIF($this->post->status == 'done', 'left', 0) - ->setIF($this->post->status == 'done' and !$this->post->finishedBy, 'finishedBy', $this->app->user->account) - ->setIF($this->post->status == 'done' and !$this->post->finishedDate, 'finishedDate', $now) - - ->setIF($this->post->status == 'cancel' and !$this->post->canceledBy, 'canceledBy', $this->app->user->account) - ->setIF($this->post->status == 'cancel' and !$this->post->canceledDate, 'canceledDate', $now) - ->setIF($this->post->status == 'cancel', 'assignedTo', $oldTask->openedBy) - ->setIF($this->post->status == 'cancel', 'assignedDate', $now) - - ->setIF($this->post->status == 'closed' and !$this->post->closedBy, 'closedBy', $this->app->user->account) - ->setIF($this->post->status == 'closed' and !$this->post->closedDate, 'closedDate', $now) - ->setIF($this->post->consumed > 0 and $this->post->left > 0 and $this->post->status == 'wait', 'status', 'doing') - - ->setIF($this->post->assignedTo != $oldTask->assignedTo, 'assignedDate', $now) - - ->setIF($this->post->status == 'wait' and $this->post->left == $oldTask->left and $this->post->consumed == 0, 'left', $this->post->estimate) - - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->remove('comment,files,labels') - ->get(); - $task->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, $task->status) + 1; - - $this->dao->update(TABLE_TASK)->data($task) - ->autoCheck() - ->batchCheckIF($task->status != 'cancel', $this->config->task->edit->requiredFields, 'notempty') - - ->checkIF($task->estimate != false, 'estimate', 'float') - ->checkIF($task->left != false, 'left', 'float') - ->checkIF($task->consumed != false, 'consumed', 'float') - ->checkIF($task->left == 0 and $task->status != 'cancel' and $task->status != 'closed', 'status', 'equal', 'done') - - ->batchCheckIF($task->status == 'wait' or $task->status == 'doing', 'finishedBy, finishedDate,canceledBy, canceledDate, closedBy, closedDate, closedReason', 'empty') - - ->checkIF($task->status == 'done', 'consumed', 'notempty') - ->checkIF($task->status == 'done' and $task->closedReason, 'closedReason', 'equal', 'done') - ->batchCheckIF($task->status == 'done', 'canceledBy, canceledDate', 'empty') - - ->checkIF($task->status == 'closed', 'closedReason', 'notempty') - ->batchCheckIF($task->closedReason == 'cancel', 'finishedBy, finishedDate', 'empty') - ->where('id')->eq((int)$taskID)->exec(); - - if($this->post->story != false) $this->loadModel('story')->setStage($this->post->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Assign a task to a user again. - * - * @param int $taskID - * @access public - * @return void - */ - public function assign($taskID) - { - $now = helper::now(); - $oldTask = $this->getById($taskID); - $this->dao->update(TABLE_TASK) - ->set('assignedTo')->eq($this->post->assignedTo) - ->set('lastEditedBy')->eq($this->app->user->account) - ->set('lastEditedDate')->eq($now) - ->where('id')->eq($taskID)->exec(); - - $actionID = $this->loadModel('action')->create('task', $taskID, 'Assigned', $this->post->comment, $this->post->assignedTo); - $this->dao->insert(TABLE_HISTORY) - ->set('company')->eq(1) - ->set('action')->eq($actionID) - ->set('field')->eq('assignedTo') - ->set('old')->eq($oldTask->assignedTo) - ->set('new')->eq($this->post->assignedTo) - ->exec(); - return $actionID; - } - - /** - * Start a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function start($taskID) - { - $oldTask = $this->getById($taskID); - $now = helper::now(); - $task = fixer::input('post') - ->setDefault('status', 'doing') - ->setDefault('lastEditedBy', $this->app->user->account) - ->setDefault('lastEditedDate', $now) - ->remove('comment')->get(); - $this->setStatus($task); - - $this->dao->update(TABLE_TASK)->data($task) - ->autoCheck() - ->check('consumed,left', 'float') - ->where('id')->eq((int)$taskID)->exec(); - - if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Finish a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function finish($taskID) - { - $oldTask = $this->getById($taskID); - $now = helper::now(); - $task = fixer::input('post') - ->setDefault('left', 0) - ->setDefault('assignedTo', $oldTask->openedBy) - ->setDefault('assignedDate', $now) - ->setDefault('status', 'done') - ->setDefault('finishedBy, lastEditedBy', $this->app->user->account) - ->setDefault('finishedDate, lastEditedDate', $now) - ->remove('comment')->get(); - $this->setStatus($task); - - $this->dao->update(TABLE_TASK)->data($task) - ->autoCheck() - ->check('consumed', 'notempty') - ->where('id')->eq((int)$taskID)->exec(); - - if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Close a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function close($taskID) - { - $oldTask = $this->getById($taskID); - $now = helper::now(); - $task = fixer::input('post') - ->setDefault('status', 'closed') - ->setDefault('assignedTo', 'closed') - ->setDefault('assignedDate', $now) - ->setDefault('closedBy, lastEditedBy', $this->app->user->account) - ->setDefault('closedDate, lastEditedDate', $now) - ->setIF($oldTask->status == 'done', 'closedReason', 'done') - ->setIF($oldTask->status == 'cancel', 'closedReason', 'cancel') - ->remove('comment')->get(); - $this->setStatus($task); - - $this->dao->update(TABLE_TASK)->data($task)->autoCheck()->where('id')->eq((int)$taskID)->exec(); - - if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Cancel a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function cancel($taskID) - { - $oldTask = $this->getById($taskID); - $now = helper::now(); - $task = fixer::input('post') - ->setDefault('status', 'cancel') - ->setDefault('assignedTo', $oldTask->openedBy) - ->setDefault('assignedDate', $now) - ->setDefault('finishedBy', '') - ->setDefault('finishedDate', '0000-00-00') - ->setDefault('canceledBy, lastEditedBy', $this->app->user->account) - ->setDefault('canceledDate, lastEditedDate', $now) - ->remove('comment')->get(); - $this->setStatus($task); - - $this->dao->update(TABLE_TASK)->data($task)->autoCheck()->where('id')->eq((int)$taskID)->exec(); - - if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Activate a task. - * - * @param int $taskID - * @access public - * @return void - */ - public function activate($taskID) - { - $oldTask = $this->getById($taskID); - $task = fixer::input('post') - ->setDefault('left', 0) - ->setDefault('status', 'doing') - ->setDefault('finishedBy, canceledBy, closedBy, closedReason', '') - ->setDefault('finishedDate, canceledDate, closedDate', '0000-00-00') - ->setDefault('lastEditedBy', $this->app->user->account) - ->setDefault('lastEditedDate', helper::now()) - ->remove('comment')->get(); - $this->setStatus($task); - - $this->dao->update(TABLE_TASK)->data($task) - ->autoCheck() - ->check('left', 'notempty') - ->where('id')->eq((int)$taskID)->exec(); - - if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); - if(!dao::isError()) return common::createChanges($oldTask, $task); - - } - - /** - * Get task info by Id. - * - * @param int $taskID - * @access public - * @return object|bool - */ - public function getById($taskID) - { - $task = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') - ->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_STORY)->alias('t2') - ->on('t1.story = t2.id') - ->leftJoin(TABLE_USER)->alias('t3') - ->on('t1.assignedTo = t3.account') - ->where('t1.id')->eq((int)$taskID) - ->fetch(); - if(!$task) return false; - $task->desc = $this->loadModel('file')->setImgSize($task->desc); - if($task->assignedTo == 'closed') $task->assignedToRealName = 'Closed'; - foreach($task as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $task->$key = ''; - if($task->mailto) - { - $task->mailto = ltrim(trim($task->mailto), ','); // remove the first , - $task->mailto = str_replace(' ', '', $task->mailto); - $task->mailto = rtrim($task->mailto, ',') . ','; - $task->mailto = str_replace(',', ', ', $task->mailto); - } - $task->files = $this->loadModel('file')->getByObject('task', $taskID); - return $this->processTask($task); - } - - /** - * Get tasks of a project. - * - * @param int $projectID - * @param string $status all|needConfirm|wait|doing|done|cancel - * @param string $type - * @param object $pager - * @access public - * @return array - */ - public function getProjectTasks($projectID, $type = 'all', $orderBy = 'status_asc, id_desc', $pager = null) - { - $orderBy = str_replace('status', 'statusCustom', $orderBy); - $type = strtolower($type); - $tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') - ->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') - ->leftJoin(TABLE_USER)->alias('t3')->on('t1.assignedTo = t3.account') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t1.deleted')->eq(0) - ->beginIF($type == 'needconfirm')->andWhere('t2.version > t1.storyVersion')->andWhere("t2.status = 'active'")->fi() - ->beginIF($type == 'assignedtome')->andWhere('t1.assignedTo')->eq($this->app->user->account)->fi() - ->beginIF($type == 'finishedbyme')->andWhere('t1.finishedby')->eq($this->app->user->account)->fi() - ->beginIF($type == 'delayed')->andWhere('deadline')->between('1970-1-1', helper::now())->andWhere('t1.status')->in('wait,doing')->fi() - ->beginIF(strpos('all|needconfirm|assignedtome|delayed|finishedbyme', $type) === false)->andWhere('t1.status')->in($type)->fi() - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - - $sql = explode('WHERE', $this->dao->get()); - $sql = explode('ORDER', $sql[1]); - $this->session->set('taskReportCondition', $sql[0]); - - if($tasks) return $this->processTasks($tasks); - return array(); - } - - /** - * Get project tasks pairs. - * - * @param int $projectID - * @param string $status - * @param string $orderBy - * @access public - * @return array - */ - public function getProjectTaskPairs($projectID, $status = 'all', $orderBy = 'finishedBy, id_desc') - { - $tasks = array('' => ''); - $stmt = $this->dao->select('t1.id, t1.name, t2.realname AS finishedByRealName') - ->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_USER)->alias('t2')->on('t1.finishedBy = t2.account') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t1.deleted')->eq(0) - ->beginIF($status != 'all')->andWhere('t1.status')->in($status)->fi() - ->orderBy($orderBy) - ->query(); - while($task = $stmt->fetch()) $tasks[$task->id] = "$task->id:$task->finishedByRealName:$task->name"; - return $tasks; - } - - /** - * Get tasks of a user. - * - * @param string $account - * @param string $type the query type - * @param int $limit - * @access public - * @return array - */ - public function getUserTasks($account, $type = 'assignedto', $limit = 0) - { - $type = strtolower($type); - $tasks = $this->dao->select('t1.*, t2.id as projectID, t2.name as projectName, t3.id as storyID, t3.title as storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion') - ->from(TABLE_TASK)->alias('t1') - ->leftjoin(TABLE_PROJECT)->alias('t2') - ->on('t1.project = t2.id') - ->leftjoin(TABLE_STORY)->alias('t3') - ->on('t1.story = t3.id') - ->where('t1.deleted')->eq(0) - ->beginIF($type == 'openedby')->andWhere('t1.openedBy')->eq($account)->fi() - ->beginIF($type == 'assignedto')->andWhere('t1.assignedto')->eq($account)->fi() - ->beginIF($type == 'finishedby')->andWhere('t1.finishedby')->eq($account)->fi() - ->beginIF($type == 'closedby')->andWhere('t1.closedby')->eq($account)->fi() - ->beginIF($type == 'canceledby')->andWhere('t1.canceledby')->eq($account)->fi() - ->orderBy('id desc') - ->beginIF($limit > 0)->limit($limit)->fi() - ->fetchAll(); - if($tasks) return $this->processTasks($tasks); - return array(); - } - - /** - * Get tasks pairs of a user. - * - * @param string $account - * @param string $status - * @access public - * @return array - */ - public function getUserTaskPairs($account, $status = 'all') - { - $tasks = array(); - $sql = $this->dao->select('t1.id, t1.name, t2.name as project') - ->from(TABLE_TASK)->alias('t1') - ->leftjoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t1.assignedTo')->eq($account) - ->andWhere('t1.deleted')->eq(0); - if($status != 'all') $sql->andwhere('t1.status')->in($status); - $stmt = $sql->query(); - while($task = $stmt->fetch()) - { - $tasks[$task->id] = $task->project . ' / ' . $task->name; - } - return $tasks; - } - - /** - * Get task pairs of a story. - * - * @param int $storyID - * @param int $projectID - * @access public - * @return array - */ - public function getStoryTaskPairs($storyID, $projectID = 0) - { - return $this->dao->select('id, name') - ->from(TABLE_TASK) - ->where('story')->eq((int)$storyID) - ->andWhere('deleted')->eq(0) - ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() - ->fetchPairs(); - } - - /** - * Get counts of some stories' tasks. - * - * @param array $stories - * @param int $projectID - * @access public - * @return int - */ - public function getStoryTaskCounts($stories, $projectID = 0) - { - $taskCounts = $this->dao->select('story, COUNT(*) AS tasks') - ->from(TABLE_TASK) - ->where('story')->in($stories) - ->andWhere('deleted')->eq(0) - ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() - ->groupBy('story') - ->fetchPairs(); - foreach($stories as $storyID) if(!isset($taskCounts[$storyID])) $taskCounts[$storyID] = 0; - return $taskCounts; - } - - /** - * Batch process tasks. - * - * @param int $tasks - * @access private - * @return void - */ - public function processTasks($tasks) - { - $today = helper::today(); - foreach($tasks as $task) - { - /* Delayed or not. */ - if($task->status !== 'done' and $task->status !== 'cancel') - { - if($task->deadline != '0000-00-00') - { - $delay = helper::diffDate($today, $task->deadline); - if($delay > 0) $task->delay = $delay; - } - } - - /* Story changed or not. */ - $task->needConfirm = false; - if($task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion) - { - $task->needConfirm = true; - } - } - return $tasks; - } - - /** - * Process a task, judge it's status. - * - * @param object $task - * @access private - * @return object - */ - public function processTask($task) - { - $today = helper::today(); - - /* Delayed or not?. */ - if($task->status !== 'done' and $task->status !== 'cancel') - { - if($task->deadline != '0000-00-00') - { - if($task->status == 'closed' && $task->closedReason == 'done') - { - if($task->finishedDate == '') $delay = helper::diffDate(substr($task->closedDate, 0, 10), $task->deadline); - if($task->finishedDate != '') $delay = helper::diffDate(substr($task->finishedDate, 0, 10), $task->deadline); - } - else - { - $delay = helper::diffDate($today, $task->deadline); - } - if($delay > 0) $task->delay = $delay; - } - } - - /* Story changed or not. */ - $task->needConfirm = false; - if($task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion) - { - $task->needConfirm = true; - } - return $task; - } - - /** - * Set the status field of a task. - * - * @param object $task - * @access private - * @return void - */ - public function setStatus($task) - { - $task->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, $task->status) + 1; - } - - /** - * Merge the default chart settings and the settings of current chart. - * - * @param string $chartType - * @access public - * @return void - */ - public function mergeChartOption($chartType) - { - $chartOption = $this->lang->task->report->$chartType; - $commonOption = $this->lang->task->report->options; - - $chartOption->graph->caption = $this->lang->task->report->charts[$chartType]; - if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; - if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; - if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; - - /* merge configuration */ - foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; - } - - /** - * Get report data of tasks per project - * - * @access public - * @return array - */ - public function getDataOftasksPerProject() - { - $datas = $this->dao->select('project as name, count(*) as value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('project') - ->orderBy('value DESC') - ->fetchAll('name'); - if(!$datas) return array(); - $projects = $this->loadModel('project')->getPairs('all'); - foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined; - return $datas; - } - - /** - * Get report data of tasks per assignedTo - * - * @access public - * @return array - */ - public function getDataOftasksPerAssignedTo() - { - $datas = $this->dao->select('assignedTo AS name, count(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('assignedTo') - ->orderBy('value DESC') - ->fetchAll('name'); - if(!$datas) return array(); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - return $datas; - } - - /** - * Get report data of tasks per type - * - * @access public - * @return array - */ - public function getDataOftasksPerType() - { - $datas = $this->dao->select('type AS name, count(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('type') - ->orderBy('value DESC') - ->fetchAll('name'); - if(!$datas) return array(); - foreach($datas as $type => $data) if(isset($this->lang->task->typeList[$type])) $data->name = $this->lang->task->typeList[$type]; - return $datas; - } - - /** - * Get report data of tasks per priority - * - * @access public - * @return array - */ - public function getDataOftasksPerPri() - { - return $this->dao->select('pri AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('pri') - ->orderBy('value DESC') - ->fetchAll('name'); - } - - /** - * Get report data of tasks per deadline - * - * @access public - * @return array - */ - public function getDataOftasksPerDeadline() - { - return $this->dao->select('deadline AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('deadline') - ->orderBy('value DESC') - ->fetchAll('name'); - } - - /** - * Get report data of tasks per estimate - * - * @access public - * @return array - */ - public function getDataOftasksPerEstimate() - { - return $this->dao->select('estimate AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('estimate') - ->orderBy('value DESC') - ->fetchAll('name'); - } - - /** - * Get report data of tasks per left - * - * @access public - * @return array - */ - public function getDataOftasksPerLeft() - { - return $this->dao->select('`left` AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('`left`') - ->orderBy('value DESC') - ->fetchAll('name'); - } - - /** - * Get report data of tasks per consumed - * - * @access public - * @return array - */ - public function getDataOftasksPerConsumed() - { - return $this->dao->select('consumed AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('consumed') - ->orderBy('value DESC') - ->fetchAll('name'); - } - - /** - * Get report data of tasks per finishedBy - * - * @access public - * @return array - */ - public function getDataOftasksPerFinishedBy() - { - $datas = $this->dao->select('finishedBy AS name, COUNT(finishedBy) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->andWhere('finishedBy')->ne('') - ->groupBy('finishedBy') - ->orderBy('value DESC') - ->fetchAll('name'); - if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); - foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; - - return $datas; - } - - /** - * Get report data of tasks per closed reason - * - * @access public - * @return array - */ - public function getDataOftasksPerClosedReason() - { - $datas = $this->dao->select('closedReason AS name, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('closedReason') - ->orderBy('value DESC') - ->fetchAll('name'); - - foreach($datas as $closedReason => $data) - { - if(isset($this->lang->task->reasonList[$closedReason])) - { - $data->name = $this->lang->task->reasonList[$closedReason]; - } - } - return $datas; - } - - /** - * Get report data of finished tasks per day - * - * @access public - * @return array - */ - public function getDataOffinishedTasksPerDay() - { - $datas= $this->dao->select('DATE_FORMAT(finishedDate, "%Y-%m-%d") AS date, COUNT(*) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('date') - ->having('date != "0000-00-00"') - ->orderBy('finishedDate') - ->fetchAll(); - - /* Change data to name, because the task table has name field, conflicts. */ - foreach($datas as $data) - { - $data->name = $data->date; - unset($data->date); - } - return $datas; - } - - /** - * Get report data of status - * - * @access public - * @return array - */ - public function getDataOftasksPerStatus() - { - $datas = $this->dao->select('status AS name, COUNT(status) AS value') - ->from(TABLE_TASK)->alias('t1') - ->where($this->session->taskReportCondition) - ->groupBy('status') - ->orderBy('value DESC') - ->fetchAll('name'); - if(!$datas)return array(); - foreach($datas as $status => $data) - { - $data->name = $this->lang->task->statusList[$status]; - } - return $datas; - } -} + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> +post->assignedTo as $assignedTo) + { + $task = fixer::input('post') + ->striptags('name') + ->add('project', (int)$projectID) + ->setDefault('estimate, left, story', 0) + ->setDefault('deadline', '0000-00-00') + ->setDefault('status', 'wait') + ->setIF($this->post->estimate != false, 'left', $this->post->estimate) + ->setForce('assignedTo', $assignedTo) + ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->setDefault('openedBy', $this->app->user->account) + ->setDefault('openedDate', helper::now()) + ->remove('after,files,labels') + ->get(); + + if($assignedTo) $task->assignedDate = helper::now(); + + $this->setStatus($task); + + $this->dao->insert(TABLE_TASK)->data($task) + ->autoCheck() + ->batchCheck($this->config->task->create->requiredFields, 'notempty') + ->checkIF($task->estimate != '', 'estimate', 'float') + ->exec(); + + if(!dao::isError()) + { + $taskID = $this->dao->lastInsertID(); + if($this->post->story) $this->loadModel('story')->setStage($this->post->story); + if(!empty($taskFile)) + { + $taskFile->objectID = $taskID; + $this->dao->insert(TABLE_FILE)->data($taskFile)->exec(); + } + else + { + $taskFileTitle = $this->loadModel('file')->saveUpload('task', $taskID); + $taskFile = $this->dao->select('*')->from(TABLE_FILE)->where('id')->eq(key($taskFileTitle))->fetch(); + unset($taskFile->id); + } + $tasksID[$assignedTo] = $taskID; + } + else + { + return false; + } + } + return $tasksID; + } + + /** + * Create a batch task. + * + * @param int $projectID + * @access public + * @return void + */ + public function batchCreate($projectID) + { + $now = helper::now(); + $tasks = fixer::input('post')->get(); + for($i = 0; $i < $this->config->task->batchCreate; $i++) + { + if($tasks->type[$i] != '' and $tasks->name[$i] != '' and $tasks->pri[$i] != 0 and $tasks->estimate[$i] != '') + { + $data[$i]->story = $tasks->story[$i] != 'same' ? $tasks->story[$i] : ($i == 0 ? 0 : $data[$i-1]->story); + $data[$i]->type = $tasks->type[$i] == 'same' ? ($i == 0 ? '' : $data[$i-1]->type) : $tasks->type[$i]; + $data[$i]->name = $tasks->name[$i]; + $data[$i]->desc = $tasks->desc[$i]; + $data[$i]->assignedTo = $tasks->assignedTo[$i]; + $data[$i]->pri = $tasks->pri[$i]; + $data[$i]->estimate = $tasks->estimate[$i]; + $data[$i]->left = $tasks->estimate[$i]; + $data[$i]->project = $projectID; + $data[$i]->deadline = '0000-00-00'; + $data[$i]->status = 'wait'; + $data[$i]->openedBy = $this->app->user->account; + $data[$i]->openedDate = $now; + $data[$i]->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, 'wait') + 1; + if($tasks->story[$i] != '') $data[$i]->storyVersion = $this->loadModel('story')->getVersion($data[$i]->story); + if($tasks->assignedTo[$i] != '') $data[$i]->assignedDate = $now; + + $this->dao->insert(TABLE_TASK)->data($data[$i]) + ->autoCheck() + ->batchCheck($this->config->task->create->requiredFields, 'notempty') + ->checkIF($data[$i]->estimate != '', 'estimate', 'float') + ->exec(); + + if(dao::isError()) + { + echo js::error(dao::getError()); + die(js::reload('parent')); + } + + $taskID = $this->dao->lastInsertID(); + if($tasks->story[$i] != false) $this->story->setStage($tasks->story[$i]); + $actionID = $this->loadModel('action')->create('task', $taskID, 'Opened', ''); + $mails[$i]->taskID = $taskID; + $mails[$i]->actionID = $actionID; + } + else + { + unset($tasks->story[$i]); + unset($tasks->type[$i]); + unset($tasks->name[$i]); + unset($tasks->desc[$i]); + unset($tasks->assignedTo[$i]); + unset($tasks->pri[$i]); + unset($tasks->estimate[$i]); + } + } + return $mails; + } + + /** + * Update a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function update($taskID) + { + $oldTask = $this->getById($taskID); + $now = helper::now(); + $task = fixer::input('post') + ->striptags('name') + ->setDefault('story, estimate, left, consumed', 0) + ->setDefault('deadline', '0000-00-00') + ->setIF($this->post->story != false and $this->post->story != $oldTask->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + + ->setIF($this->post->status == 'done', 'left', 0) + ->setIF($this->post->status == 'done' and !$this->post->finishedBy, 'finishedBy', $this->app->user->account) + ->setIF($this->post->status == 'done' and !$this->post->finishedDate, 'finishedDate', $now) + + ->setIF($this->post->status == 'cancel' and !$this->post->canceledBy, 'canceledBy', $this->app->user->account) + ->setIF($this->post->status == 'cancel' and !$this->post->canceledDate, 'canceledDate', $now) + ->setIF($this->post->status == 'cancel', 'assignedTo', $oldTask->openedBy) + ->setIF($this->post->status == 'cancel', 'assignedDate', $now) + + ->setIF($this->post->status == 'closed' and !$this->post->closedBy, 'closedBy', $this->app->user->account) + ->setIF($this->post->status == 'closed' and !$this->post->closedDate, 'closedDate', $now) + ->setIF($this->post->consumed > 0 and $this->post->left > 0 and $this->post->status == 'wait', 'status', 'doing') + + ->setIF($this->post->assignedTo != $oldTask->assignedTo, 'assignedDate', $now) + + ->setIF($this->post->status == 'wait' and $this->post->left == $oldTask->left and $this->post->consumed == 0, 'left', $this->post->estimate) + + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->remove('comment,files,labels') + ->get(); + $task->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, $task->status) + 1; + + $this->dao->update(TABLE_TASK)->data($task) + ->autoCheck() + ->batchCheckIF($task->status != 'cancel', $this->config->task->edit->requiredFields, 'notempty') + + ->checkIF($task->estimate != false, 'estimate', 'float') + ->checkIF($task->left != false, 'left', 'float') + ->checkIF($task->consumed != false, 'consumed', 'float') + ->checkIF($task->left == 0 and $task->status != 'cancel' and $task->status != 'closed', 'status', 'equal', 'done') + + ->batchCheckIF($task->status == 'wait' or $task->status == 'doing', 'finishedBy, finishedDate,canceledBy, canceledDate, closedBy, closedDate, closedReason', 'empty') + + ->checkIF($task->status == 'done', 'consumed', 'notempty') + ->checkIF($task->status == 'done' and $task->closedReason, 'closedReason', 'equal', 'done') + ->batchCheckIF($task->status == 'done', 'canceledBy, canceledDate', 'empty') + + ->checkIF($task->status == 'closed', 'closedReason', 'notempty') + ->batchCheckIF($task->closedReason == 'cancel', 'finishedBy, finishedDate', 'empty') + ->where('id')->eq((int)$taskID)->exec(); + + if($this->post->story != false) $this->loadModel('story')->setStage($this->post->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Assign a task to a user again. + * + * @param int $taskID + * @access public + * @return void + */ + public function assign($taskID) + { + $now = helper::now(); + $oldTask = $this->getById($taskID); + $this->dao->update(TABLE_TASK) + ->set('assignedTo')->eq($this->post->assignedTo) + ->set('lastEditedBy')->eq($this->app->user->account) + ->set('lastEditedDate')->eq($now) + ->where('id')->eq($taskID)->exec(); + + $actionID = $this->loadModel('action')->create('task', $taskID, 'Assigned', $this->post->comment, $this->post->assignedTo); + $this->dao->insert(TABLE_HISTORY) + ->set('company')->eq(1) + ->set('action')->eq($actionID) + ->set('field')->eq('assignedTo') + ->set('old')->eq($oldTask->assignedTo) + ->set('new')->eq($this->post->assignedTo) + ->exec(); + return $actionID; + } + + /** + * Start a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function start($taskID) + { + $oldTask = $this->getById($taskID); + $now = helper::now(); + $task = fixer::input('post') + ->setDefault('status', 'doing') + ->setDefault('lastEditedBy', $this->app->user->account) + ->setDefault('lastEditedDate', $now) + ->remove('comment')->get(); + $this->setStatus($task); + + $this->dao->update(TABLE_TASK)->data($task) + ->autoCheck() + ->check('consumed,left', 'float') + ->where('id')->eq((int)$taskID)->exec(); + + if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Finish a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function finish($taskID) + { + $oldTask = $this->getById($taskID); + $now = helper::now(); + $task = fixer::input('post') + ->setDefault('left', 0) + ->setDefault('assignedTo', $oldTask->openedBy) + ->setDefault('assignedDate', $now) + ->setDefault('status', 'done') + ->setDefault('finishedBy, lastEditedBy', $this->app->user->account) + ->setDefault('finishedDate, lastEditedDate', $now) + ->remove('comment')->get(); + $this->setStatus($task); + + $this->dao->update(TABLE_TASK)->data($task) + ->autoCheck() + ->check('consumed', 'notempty') + ->where('id')->eq((int)$taskID)->exec(); + + if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Close a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function close($taskID) + { + $oldTask = $this->getById($taskID); + $now = helper::now(); + $task = fixer::input('post') + ->setDefault('status', 'closed') + ->setDefault('assignedTo', 'closed') + ->setDefault('assignedDate', $now) + ->setDefault('closedBy, lastEditedBy', $this->app->user->account) + ->setDefault('closedDate, lastEditedDate', $now) + ->setIF($oldTask->status == 'done', 'closedReason', 'done') + ->setIF($oldTask->status == 'cancel', 'closedReason', 'cancel') + ->remove('comment')->get(); + $this->setStatus($task); + + $this->dao->update(TABLE_TASK)->data($task)->autoCheck()->where('id')->eq((int)$taskID)->exec(); + + if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Cancel a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function cancel($taskID) + { + $oldTask = $this->getById($taskID); + $now = helper::now(); + $task = fixer::input('post') + ->setDefault('status', 'cancel') + ->setDefault('assignedTo', $oldTask->openedBy) + ->setDefault('assignedDate', $now) + ->setDefault('finishedBy', '') + ->setDefault('finishedDate', '0000-00-00') + ->setDefault('canceledBy, lastEditedBy', $this->app->user->account) + ->setDefault('canceledDate, lastEditedDate', $now) + ->remove('comment')->get(); + $this->setStatus($task); + + $this->dao->update(TABLE_TASK)->data($task)->autoCheck()->where('id')->eq((int)$taskID)->exec(); + + if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Activate a task. + * + * @param int $taskID + * @access public + * @return void + */ + public function activate($taskID) + { + $oldTask = $this->getById($taskID); + $task = fixer::input('post') + ->setDefault('left', 0) + ->setDefault('status', 'doing') + ->setDefault('finishedBy, canceledBy, closedBy, closedReason', '') + ->setDefault('finishedDate, canceledDate, closedDate', '0000-00-00') + ->setDefault('lastEditedBy', $this->app->user->account) + ->setDefault('lastEditedDate', helper::now()) + ->remove('comment')->get(); + $this->setStatus($task); + + $this->dao->update(TABLE_TASK)->data($task) + ->autoCheck() + ->check('left', 'notempty') + ->where('id')->eq((int)$taskID)->exec(); + + if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story); + if(!dao::isError()) return common::createChanges($oldTask, $task); + + } + + /** + * Get task info by Id. + * + * @param int $taskID + * @access public + * @return object|bool + */ + public function getById($taskID) + { + $task = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') + ->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2') + ->on('t1.story = t2.id') + ->leftJoin(TABLE_USER)->alias('t3') + ->on('t1.assignedTo = t3.account') + ->where('t1.id')->eq((int)$taskID) + ->fetch(); + if(!$task) return false; + $task->desc = $this->loadModel('file')->setImgSize($task->desc); + if($task->assignedTo == 'closed') $task->assignedToRealName = 'Closed'; + foreach($task as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $task->$key = ''; + if($task->mailto) + { + $task->mailto = ltrim(trim($task->mailto), ','); // remove the first , + $task->mailto = str_replace(' ', '', $task->mailto); + $task->mailto = rtrim($task->mailto, ',') . ','; + $task->mailto = str_replace(',', ', ', $task->mailto); + } + $task->files = $this->loadModel('file')->getByObject('task', $taskID); + return $this->processTask($task); + } + + /** + * Get tasks of a project. + * + * @param int $projectID + * @param string $status all|needConfirm|wait|doing|done|cancel + * @param string $type + * @param object $pager + * @access public + * @return array + */ + public function getProjectTasks($projectID, $type = 'all', $orderBy = 'status_asc, id_desc', $pager = null) + { + $orderBy = str_replace('status', 'statusCustom', $orderBy); + $type = strtolower($type); + $tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName') + ->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->leftJoin(TABLE_USER)->alias('t3')->on('t1.assignedTo = t3.account') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t1.deleted')->eq(0) + ->beginIF($type == 'needconfirm')->andWhere('t2.version > t1.storyVersion')->andWhere("t2.status = 'active'")->fi() + ->beginIF($type == 'assignedtome')->andWhere('t1.assignedTo')->eq($this->app->user->account)->fi() + ->beginIF($type == 'finishedbyme')->andWhere('t1.finishedby')->eq($this->app->user->account)->fi() + ->beginIF($type == 'delayed')->andWhere('deadline')->between('1970-1-1', helper::now())->andWhere('t1.status')->in('wait,doing')->fi() + ->beginIF(strpos('all|needconfirm|assignedtome|delayed|finishedbyme', $type) === false)->andWhere('t1.status')->in($type)->fi() + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + + $sql = explode('WHERE', $this->dao->get()); + $sql = explode('ORDER', $sql[1]); + $this->session->set('taskReportCondition', $sql[0]); + + if($tasks) return $this->processTasks($tasks); + return array(); + } + + /** + * Get project tasks pairs. + * + * @param int $projectID + * @param string $status + * @param string $orderBy + * @access public + * @return array + */ + public function getProjectTaskPairs($projectID, $status = 'all', $orderBy = 'finishedBy, id_desc') + { + $tasks = array('' => ''); + $stmt = $this->dao->select('t1.id, t1.name, t2.realname AS finishedByRealName') + ->from(TABLE_TASK)->alias('t1') + ->leftJoin(TABLE_USER)->alias('t2')->on('t1.finishedBy = t2.account') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t1.deleted')->eq(0) + ->beginIF($status != 'all')->andWhere('t1.status')->in($status)->fi() + ->orderBy($orderBy) + ->query(); + while($task = $stmt->fetch()) $tasks[$task->id] = "$task->id:$task->finishedByRealName:$task->name"; + return $tasks; + } + + /** + * Get tasks of a user. + * + * @param string $account + * @param string $type the query type + * @param int $limit + * @access public + * @return array + */ + public function getUserTasks($account, $type = 'assignedto', $limit = 0) + { + $type = strtolower($type); + $tasks = $this->dao->select('t1.*, t2.id as projectID, t2.name as projectName, t3.id as storyID, t3.title as storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion') + ->from(TABLE_TASK)->alias('t1') + ->leftjoin(TABLE_PROJECT)->alias('t2') + ->on('t1.project = t2.id') + ->leftjoin(TABLE_STORY)->alias('t3') + ->on('t1.story = t3.id') + ->where('t1.deleted')->eq(0) + ->beginIF($type == 'openedby')->andWhere('t1.openedBy')->eq($account)->fi() + ->beginIF($type == 'assignedto')->andWhere('t1.assignedto')->eq($account)->fi() + ->beginIF($type == 'finishedby')->andWhere('t1.finishedby')->eq($account)->fi() + ->beginIF($type == 'closedby')->andWhere('t1.closedby')->eq($account)->fi() + ->beginIF($type == 'canceledby')->andWhere('t1.canceledby')->eq($account)->fi() + ->orderBy('id desc') + ->beginIF($limit > 0)->limit($limit)->fi() + ->fetchAll(); + if($tasks) return $this->processTasks($tasks); + return array(); + } + + /** + * Get tasks pairs of a user. + * + * @param string $account + * @param string $status + * @access public + * @return array + */ + public function getUserTaskPairs($account, $status = 'all') + { + $tasks = array(); + $sql = $this->dao->select('t1.id, t1.name, t2.name as project') + ->from(TABLE_TASK)->alias('t1') + ->leftjoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.assignedTo')->eq($account) + ->andWhere('t1.deleted')->eq(0); + if($status != 'all') $sql->andwhere('t1.status')->in($status); + $stmt = $sql->query(); + while($task = $stmt->fetch()) + { + $tasks[$task->id] = $task->project . ' / ' . $task->name; + } + return $tasks; + } + + /** + * Get task pairs of a story. + * + * @param int $storyID + * @param int $projectID + * @access public + * @return array + */ + public function getStoryTaskPairs($storyID, $projectID = 0) + { + return $this->dao->select('id, name') + ->from(TABLE_TASK) + ->where('story')->eq((int)$storyID) + ->andWhere('deleted')->eq(0) + ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() + ->fetchPairs(); + } + + /** + * Get counts of some stories' tasks. + * + * @param array $stories + * @param int $projectID + * @access public + * @return int + */ + public function getStoryTaskCounts($stories, $projectID = 0) + { + $taskCounts = $this->dao->select('story, COUNT(*) AS tasks') + ->from(TABLE_TASK) + ->where('story')->in($stories) + ->andWhere('deleted')->eq(0) + ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() + ->groupBy('story') + ->fetchPairs(); + foreach($stories as $storyID) if(!isset($taskCounts[$storyID])) $taskCounts[$storyID] = 0; + return $taskCounts; + } + + /** + * Batch process tasks. + * + * @param int $tasks + * @access private + * @return void + */ + public function processTasks($tasks) + { + $today = helper::today(); + foreach($tasks as $task) + { + /* Delayed or not. */ + if($task->status !== 'done' and $task->status !== 'cancel') + { + if($task->deadline != '0000-00-00') + { + $delay = helper::diffDate($today, $task->deadline); + if($delay > 0) $task->delay = $delay; + } + } + + /* Story changed or not. */ + $task->needConfirm = false; + if($task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion) + { + $task->needConfirm = true; + } + } + return $tasks; + } + + /** + * Process a task, judge it's status. + * + * @param object $task + * @access private + * @return object + */ + public function processTask($task) + { + $today = helper::today(); + + /* Delayed or not?. */ + if($task->status !== 'done' and $task->status !== 'cancel') + { + if($task->deadline != '0000-00-00') + { + if($task->status == 'closed' && $task->closedReason == 'done') + { + if($task->finishedDate == '') $delay = helper::diffDate(substr($task->closedDate, 0, 10), $task->deadline); + if($task->finishedDate != '') $delay = helper::diffDate(substr($task->finishedDate, 0, 10), $task->deadline); + } + else + { + $delay = helper::diffDate($today, $task->deadline); + } + if($delay > 0) $task->delay = $delay; + } + } + + /* Story changed or not. */ + $task->needConfirm = false; + if($task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion) + { + $task->needConfirm = true; + } + return $task; + } + + /** + * Set the status field of a task. + * + * @param object $task + * @access private + * @return void + */ + public function setStatus($task) + { + $task->statusCustom = strpos(self::CUSTOM_STATUS_ORDER, $task->status) + 1; + } + + /** + * Merge the default chart settings and the settings of current chart. + * + * @param string $chartType + * @access public + * @return void + */ + public function mergeChartOption($chartType) + { + $chartOption = $this->lang->task->report->$chartType; + $commonOption = $this->lang->task->report->options; + + $chartOption->graph->caption = $this->lang->task->report->charts[$chartType]; + if(!isset($chartOption->swf)) $chartOption->swf = $commonOption->swf; + if(!isset($chartOption->width)) $chartOption->width = $commonOption->width; + if(!isset($chartOption->height)) $chartOption->height = $commonOption->height; + + /* merge configuration */ + foreach($commonOption->graph as $key => $value) if(!isset($chartOption->graph->$key)) $chartOption->graph->$key = $value; + } + + /** + * Get report data of tasks per project + * + * @access public + * @return array + */ + public function getDataOftasksPerProject() + { + $datas = $this->dao->select('project as name, count(*) as value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('project') + ->orderBy('value DESC') + ->fetchAll('name'); + if(!$datas) return array(); + $projects = $this->loadModel('project')->getPairs('all'); + foreach($datas as $projectID => $data) $data->name = isset($projects[$projectID]) ? $projects[$projectID] : $this->lang->report->undefined; + return $datas; + } + + /** + * Get report data of tasks per assignedTo + * + * @access public + * @return array + */ + public function getDataOftasksPerAssignedTo() + { + $datas = $this->dao->select('assignedTo AS name, count(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('assignedTo') + ->orderBy('value DESC') + ->fetchAll('name'); + if(!$datas) return array(); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + return $datas; + } + + /** + * Get report data of tasks per type + * + * @access public + * @return array + */ + public function getDataOftasksPerType() + { + $datas = $this->dao->select('type AS name, count(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('type') + ->orderBy('value DESC') + ->fetchAll('name'); + if(!$datas) return array(); + foreach($datas as $type => $data) if(isset($this->lang->task->typeList[$type])) $data->name = $this->lang->task->typeList[$type]; + return $datas; + } + + /** + * Get report data of tasks per priority + * + * @access public + * @return array + */ + public function getDataOftasksPerPri() + { + return $this->dao->select('pri AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('pri') + ->orderBy('value DESC') + ->fetchAll('name'); + } + + /** + * Get report data of tasks per deadline + * + * @access public + * @return array + */ + public function getDataOftasksPerDeadline() + { + return $this->dao->select('deadline AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('deadline') + ->orderBy('value DESC') + ->fetchAll('name'); + } + + /** + * Get report data of tasks per estimate + * + * @access public + * @return array + */ + public function getDataOftasksPerEstimate() + { + return $this->dao->select('estimate AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('estimate') + ->orderBy('value DESC') + ->fetchAll('name'); + } + + /** + * Get report data of tasks per left + * + * @access public + * @return array + */ + public function getDataOftasksPerLeft() + { + return $this->dao->select('`left` AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('`left`') + ->orderBy('value DESC') + ->fetchAll('name'); + } + + /** + * Get report data of tasks per consumed + * + * @access public + * @return array + */ + public function getDataOftasksPerConsumed() + { + return $this->dao->select('consumed AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('consumed') + ->orderBy('value DESC') + ->fetchAll('name'); + } + + /** + * Get report data of tasks per finishedBy + * + * @access public + * @return array + */ + public function getDataOftasksPerFinishedBy() + { + $datas = $this->dao->select('finishedBy AS name, COUNT(finishedBy) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->andWhere('finishedBy')->ne('') + ->groupBy('finishedBy') + ->orderBy('value DESC') + ->fetchAll('name'); + if(!isset($this->users)) $this->users = $this->loadModel('user')->getPairs('noletter'); + foreach($datas as $account => $data) if(isset($this->users[$account])) $data->name = $this->users[$account]; + + return $datas; + } + + /** + * Get report data of tasks per closed reason + * + * @access public + * @return array + */ + public function getDataOftasksPerClosedReason() + { + $datas = $this->dao->select('closedReason AS name, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('closedReason') + ->orderBy('value DESC') + ->fetchAll('name'); + + foreach($datas as $closedReason => $data) + { + if(isset($this->lang->task->reasonList[$closedReason])) + { + $data->name = $this->lang->task->reasonList[$closedReason]; + } + } + return $datas; + } + + /** + * Get report data of finished tasks per day + * + * @access public + * @return array + */ + public function getDataOffinishedTasksPerDay() + { + $datas= $this->dao->select('DATE_FORMAT(finishedDate, "%Y-%m-%d") AS date, COUNT(*) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('date') + ->having('date != "0000-00-00"') + ->orderBy('finishedDate') + ->fetchAll(); + + /* Change data to name, because the task table has name field, conflicts. */ + foreach($datas as $data) + { + $data->name = $data->date; + unset($data->date); + } + return $datas; + } + + /** + * Get report data of status + * + * @access public + * @return array + */ + public function getDataOftasksPerStatus() + { + $datas = $this->dao->select('status AS name, COUNT(status) AS value') + ->from(TABLE_TASK)->alias('t1') + ->where($this->session->taskReportCondition) + ->groupBy('status') + ->orderBy('value DESC') + ->fetchAll('name'); + if(!$datas)return array(); + foreach($datas as $status => $data) + { + $data->name = $this->lang->task->statusList[$status]; + } + return $datas; + } +} diff --git a/module/task/view/activate.html.php b/module/task/view/activate.html.php index 77d2c65ee3..b3d76c6e93 100644 --- a/module/task/view/activate.html.php +++ b/module/task/view/activate.html.php @@ -1,40 +1,40 @@ - - * @package task - * @version $Id: start.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - - - - -
          name;?>
          task->assignedTo;?>finishedBy, "class='select-3'");?>
          task->left;?>
          comment;?>
          - goback, $this->session->taskList); - ?> -
          - -
          - + + * @package task + * @version $Id: start.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + + + + +
          name;?>
          task->assignedTo;?>finishedBy, "class='select-3'");?>
          task->left;?>
          comment;?>
          + goback, $this->session->taskList); + ?> +
          + +
          + diff --git a/module/task/view/assignto.html.php b/module/task/view/assignto.html.php index 633ff17d1f..edd22edb92 100644 --- a/module/task/view/assignto.html.php +++ b/module/task/view/assignto.html.php @@ -1,31 +1,31 @@ - - * @package task - * @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - -
          name;?>
          task->assignedTo;?>
          comment;?>
          goback, $this->session->taskList);?>
          - -
          - + + * @package task + * @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + +
          name;?>
          task->assignedTo;?>
          comment;?>
          goback, $this->session->taskList);?>
          + +
          + diff --git a/module/task/view/batchcreate.html.php b/module/task/view/batchcreate.html.php index 7a1fa8f6b6..c3ee154275 100644 --- a/module/task/view/batchcreate.html.php +++ b/module/task/view/batchcreate.html.php @@ -1,51 +1,51 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - task->batchCreate; $i++):?> - - task->typeList['same'] = $lang->task->same; $type = $i == 0 ? '' : 'same';?> - - - - - - - - - - - - - - - - -
          task->project . $lang->colon . $lang->task->batchCreate;?>
          idAB;?>task->story;?>task->name;?>task->desc;?>typeAB;?>task->assignedTo;?>task->pri;?>task->estimate;?>
          *";?>task->typeList, $type, 'class=select-1'); echo "*";?>task->priList, $pri, 'class=select-1'); echo "*";?>*";?>
          -
          task->notes;?>
          -
          -
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + task->batchCreate; $i++):?> + + task->typeList['same'] = $lang->task->same; $type = $i == 0 ? '' : 'same';?> + + + + + + + + + + + + + + + + +
          task->project . $lang->colon . $lang->task->batchCreate;?>
          idAB;?>task->story;?>task->name;?>task->desc;?>typeAB;?>task->assignedTo;?>task->pri;?>task->estimate;?>
          *";?>task->typeList, $type, 'class=select-1'); echo "*";?>task->priList, $pri, 'class=select-1'); echo "*";?>*";?>
          +
          task->notes;?>
          +
          +
          +
          + diff --git a/module/task/view/browse.html.php b/module/task/view/browse.html.php index d4fdf5bba5..43402665c4 100644 --- a/module/task/view/browse.html.php +++ b/module/task/view/browse.html.php @@ -1,36 +1,36 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - -
          task->browse;?>
          task->id;?>task->name;?>task->assignedTo;?>
          id;?>name;?>assignedTo;?>
          - createLink($this->moduleName, 'create', $vars); - echo "{$lang->task->create}"; - ?> -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + +
          task->browse;?>
          task->id;?>task->name;?>task->assignedTo;?>
          id;?>name;?>assignedTo;?>
          + createLink($this->moduleName, 'create', $vars); + echo "{$lang->task->create}"; + ?> +
          + diff --git a/module/task/view/cancel.html.php b/module/task/view/cancel.html.php index 22625cd245..99069becda 100644 --- a/module/task/view/cancel.html.php +++ b/module/task/view/cancel.html.php @@ -1,27 +1,27 @@ - - * @package task - * @version $Id: cancel.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - -
          name;?>
          comment;?>
          goback, $this->session->taskList);?>;
          - -
          - + + * @package task + * @version $Id: cancel.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + +
          name;?>
          comment;?>
          goback, $this->session->taskList);?>;
          + +
          + diff --git a/module/task/view/close.html.php b/module/task/view/close.html.php index fcc918d8ed..33627e458e 100644 --- a/module/task/view/close.html.php +++ b/module/task/view/close.html.php @@ -1,27 +1,27 @@ - - * @package task - * @version $Id: cancel.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - -
          name;?>
          comment;?>
          goback, $this->session->taskList);?>
          - -
          - + + * @package task + * @version $Id: cancel.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + +
          name;?>
          comment;?>
          goback, $this->session->taskList);?>
          + +
          + diff --git a/module/task/view/create.html.php b/module/task/view/create.html.php index 1bd3764901..5c51705154 100644 --- a/module/task/view/create.html.php +++ b/module/task/view/create.html.php @@ -1,86 +1,86 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          task->create;?>
          task->project;?>name;?>
          task->assignedTo;?>
          task->story;?> - - preview;?> -
          task->name;?> - task->copyStoryTitle, 'onclick=copyStoryTitle()');?> -
          task->desc;?>
          task->pri;?>task->priList, '', 'class=select-3');?> -
          task->estimate;?>
          task->deadline;?>
          task->type;?>task->typeList, '', 'class=select-3 onchange="setOwners(this.value)"');?>
          task->mailto;?>
          files;?>fetch('file', 'buildform');?>
          task->afterSubmit;?>task->afterChoices, 'continueAdding');?>
          -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          task->create;?>
          task->project;?>name;?>
          task->assignedTo;?>
          task->story;?> + + preview;?> +
          task->name;?> + task->copyStoryTitle, 'onclick=copyStoryTitle()');?> +
          task->desc;?>
          task->pri;?>task->priList, '', 'class=select-3');?> +
          task->estimate;?>
          task->deadline;?>
          task->type;?>task->typeList, '', 'class=select-3 onchange="setOwners(this.value)"');?>
          task->mailto;?>
          files;?>fetch('file', 'buildform');?>
          task->afterSubmit;?>task->afterChoices, 'continueAdding');?>
          +
          + diff --git a/module/task/view/edit.html.php b/module/task/view/edit.html.php index f079258339..bc256897e6 100644 --- a/module/task/view/edit.html.php +++ b/module/task/view/edit.html.php @@ -1,145 +1,145 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          -
          -
          TASK #id . $lang->colon . html::input('name', $task->name, 'class="text-1"');?>
          -
          -
          - - - - - - - -
          - - -
          -
          - task->desc;?> - desc), "rows='8' class='area-1'");?> -
          -
          - comment;?> - -
          -
          - files;?> - fetch('file', 'buildform');?> -
          -
          -
          goback, $this->inlink('view', "taskID=$task->id"));?>
          - -
          -
          - task->legendBasic;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          task->project;?>name;?>
          task->story;?>
          story, 'class=select-1');?>
          - createLink('search', 'select', "productID=0&projectID=$project->id&module=story&storyID=$task->story"), $lang->go, "_blank", "class='search' id='searchStories'");?> -
          task->assignedTo;?>assignedTo, 'class=select-1');?> -
          task->type;?>task->typeList, $task->type, 'class=select-1');?>
          task->status;?>task->statusList, $task->status, 'class=select-1');?>
          task->pri;?>task->priList, $task->pri, 'class=select-1');?> -
          task->mailto;?>mailto, 'class="text-1"');?>
          -
          -
          - task->legendEffort;?> - - - - - - - - - - - - - - - - - -
          task->deadline;?>deadline, "class='text-1 date'");?>
          task->estimate;?>estimate, "class='text-1'");?>
          task->consumed;?>consumed, "class='text-1'");?>
          task->left;?>left, "class='text-1'");?>
          -
          -
          - task->legendLife;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          task->openedBy;?>openedBy];?>
          task->finishedBy;?>finishedBy, 'class="select-1"');?>
          task->finishedDate;?>finishedDate, 'class="text-1"');?>
          task->canceledBy;?>canceledBy, 'class="select-1"');?>
          task->canceledDate;?>canceledDate, 'class="text-1"');?>
          task->closedBy;?>closedBy, 'class="select-1"');?>
          task->closedReason;?>task->reasonList, $task->closedReason, 'class="select-1"');?>
          task->closedDate;?>closedDate, 'class="text-1"');?>
          -
          -
          -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          +
          +
          TASK #id . $lang->colon . html::input('name', $task->name, 'class="text-1"');?>
          +
          +
          + + + + + + + +
          + + +
          +
          + task->desc;?> + desc), "rows='8' class='area-1'");?> +
          +
          + comment;?> + +
          +
          + files;?> + fetch('file', 'buildform');?> +
          +
          +
          goback, $this->inlink('view', "taskID=$task->id"));?>
          + +
          +
          + task->legendBasic;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          task->project;?>name;?>
          task->story;?>
          story, 'class=select-1');?>
          + createLink('search', 'select', "productID=0&projectID=$project->id&module=story&storyID=$task->story"), $lang->go, "_blank", "class='search' id='searchStories'");?> +
          task->assignedTo;?>assignedTo, 'class=select-1');?> +
          task->type;?>task->typeList, $task->type, 'class=select-1');?>
          task->status;?>task->statusList, $task->status, 'class=select-1');?>
          task->pri;?>task->priList, $task->pri, 'class=select-1');?> +
          task->mailto;?>mailto, 'class="text-1"');?>
          +
          +
          + task->legendEffort;?> + + + + + + + + + + + + + + + + + +
          task->deadline;?>deadline, "class='text-1 date'");?>
          task->estimate;?>estimate, "class='text-1'");?>
          task->consumed;?>consumed, "class='text-1'");?>
          task->left;?>left, "class='text-1'");?>
          +
          +
          + task->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          task->openedBy;?>openedBy];?>
          task->finishedBy;?>finishedBy, 'class="select-1"');?>
          task->finishedDate;?>finishedDate, 'class="text-1"');?>
          task->canceledBy;?>canceledBy, 'class="select-1"');?>
          task->canceledDate;?>canceledDate, 'class="text-1"');?>
          task->closedBy;?>closedBy, 'class="select-1"');?>
          task->closedReason;?>task->reasonList, $task->closedReason, 'class="select-1"');?>
          task->closedDate;?>closedDate, 'class="text-1"');?>
          +
          +
          +
          + diff --git a/module/task/view/export.html.php b/module/task/view/export.html.php index 4ede69eed3..81a6aeff3d 100755 --- a/module/task/view/export.html.php +++ b/module/task/view/export.html.php @@ -1,13 +1,13 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + diff --git a/module/task/view/finish.html.php b/module/task/view/finish.html.php index 3b8e99700a..888b9d6574 100644 --- a/module/task/view/finish.html.php +++ b/module/task/view/finish.html.php @@ -1,31 +1,31 @@ - - * @package task - * @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - -
          name;?>
          task->consumed;?>consumed, "class='text-3'");?>
          comment;?>
          goback, $this->session->taskList);?>
          - -
          - + + * @package task + * @version $Id: complete.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + +
          name;?>
          task->consumed;?>consumed, "class='text-3'");?>
          comment;?>
          goback, $this->session->taskList);?>
          + +
          + diff --git a/module/task/view/import.html.php b/module/task/view/import.html.php index 08bd2e5109..99527942ac 100644 --- a/module/task/view/import.html.php +++ b/module/task/view/import.html.php @@ -1,58 +1,58 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - assignedTo == $app->user->account ? 'style=color:red' : '';?> - - - - - - - - - - - - - - - -
          task->id;?>task->pri;?>task->name;?>task->assignedTo;?>task->estimate;?>task->consumed;?>task->left;?>task->type;?>task->status;?>task->story;?>actions;?>
          createLink('task', 'view', "task=$task->id"), sprintf('%03d', $task->id)); else printf('%03d', $task->id);?>pri;?>name;?>>assignedToRealName;?>estimate;?>consumed;?>left;?>task->typeList[$task->type];?>status;?> >task->statusList->{$task->status};?> - storyID) - { - if(common::hasPriv('story', 'view')) echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); - else echo $task->storyTitle; - } - ?> - -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + assignedTo == $app->user->account ? 'style=color:red' : '';?> + + + + + + + + + + + + + + + +
          task->id;?>task->pri;?>task->name;?>task->assignedTo;?>task->estimate;?>task->consumed;?>task->left;?>task->type;?>task->status;?>task->story;?>actions;?>
          createLink('task', 'view', "task=$task->id"), sprintf('%03d', $task->id)); else printf('%03d', $task->id);?>pri;?>name;?>>assignedToRealName;?>estimate;?>consumed;?>left;?>task->typeList[$task->type];?>status;?> >task->statusList->{$task->status};?> + storyID) + { + if(common::hasPriv('story', 'view')) echo html::a($this->createLink('story', 'view', "storyid=$task->storyID"), $task->storyTitle); + else echo $task->storyTitle; + } + ?> + +
          + diff --git a/module/task/view/report.html.php b/module/task/view/report.html.php index d2d34dea6c..bc381b7401 100644 --- a/module/task/view/report.html.php +++ b/module/task/view/report.html.php @@ -1,63 +1,63 @@ - - * @package project - * @version $Id: report.html.php 1594 2011-04-10 11:00:00Z wj $ - * @link http://www.zentao.net - */ -?> - -
          -
          report->common;?>
          -
          goback); ?>
          -
          - - - - - - - -
          -
          task->report->select;?>
          -
          -
          - task->report->charts, $checkedCharts)?> - - -

          - task->report->create);?> -
          -
          -
          - - - $chartContent):?> - - - - - -
          task->report->common;?>
          - - - - - - - $data):?> - - - - - - -
          report->item;?>report->value;?>report->percent;?>
          name;?>value;?>percent * 100) . '%';?>
          -
          -
          - - + + * @package project + * @version $Id: report.html.php 1594 2011-04-10 11:00:00Z wj $ + * @link http://www.zentao.net + */ +?> + +
          +
          report->common;?>
          +
          goback); ?>
          +
          + + + + + + + +
          +
          task->report->select;?>
          +
          +
          + task->report->charts, $checkedCharts)?> + + +

          + task->report->create);?> +
          +
          +
          + + + $chartContent):?> + + + + + +
          task->report->common;?>
          + + + + + + + $data):?> + + + + + + +
          report->item;?>report->value;?>report->percent;?>
          name;?>value;?>percent * 100) . '%';?>
          +
          +
          + + diff --git a/module/task/view/sendmail.html.php b/module/task/view/sendmail.html.php index a29d8c6cd6..48c8d57dcf 100644 --- a/module/task/view/sendmail.html.php +++ b/module/task/view/sendmail.html.php @@ -1,22 +1,22 @@ - - * @package task - * @version $Id: sendmail.html.php 867 2010-06-17 09:32:58Z yuren_@126.com $ - * @link http://www.zentao.net - */ -?> - - - - - - - -
          - TASK #id . "=>$task->assignedTo " . html::a(common::getSysURL() . $this->createLink('task', 'view', "taskID=$task->id"), $task->name);?> -
          + + * @package task + * @version $Id: sendmail.html.php 867 2010-06-17 09:32:58Z yuren_@126.com $ + * @link http://www.zentao.net + */ +?> + + + + + + + +
          + TASK #id . "=>$task->assignedTo " . html::a(common::getSysURL() . $this->createLink('task', 'view', "taskID=$task->id"), $task->name);?> +
          diff --git a/module/task/view/start.html.php b/module/task/view/start.html.php index 2786789be4..500e173e9d 100644 --- a/module/task/view/start.html.php +++ b/module/task/view/start.html.php @@ -1,35 +1,35 @@ - - * @package task - * @version $Id: start.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - - - - -
          name;?>
          task->consumed;?>consumed, "class='text-3'");?>
          task->left;?>left, "class='text-3'");?>
          comment;?>
          goback, $this->session->taskList); ?>
          - -
          - + + * @package task + * @version $Id: start.html.php 935 2010-07-06 07:49:24Z jajacn@126.com $ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + + + + +
          name;?>
          task->consumed;?>consumed, "class='text-3'");?>
          task->left;?>left, "class='text-3'");?>
          comment;?>
          goback, $this->session->taskList); ?>
          + +
          + diff --git a/module/task/view/view.html.php b/module/task/view/view.html.php index 8386046ca8..fe06f2129f 100644 --- a/module/task/view/view.html.php +++ b/module/task/view/view.html.php @@ -1,182 +1,182 @@ - - * @package task - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -fromBug == 0):?> -
          '>TASK #id . $lang->colon . $task->name;?>
          - -
          '>TASK #id . $lang->colon . $task->name . '('. $lang->task->fromBug . $lang->colon . $task->fromBug . ')';?>
          - -
          - session->taskList != false ? $app->session->taskList : $this->createLink('project', 'browse', "projectID=$task->project"); - if(!$task->deleted) - { - //if(!($task->status != 'closed' and $task->status != 'cancel' and common::printLink('task', 'logEfforts', "taskID=$task->id", $lang->task->buttonLogEfforts))) echo $lang->task->buttonLogEfforts . ' '; - if(!(($task->status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; - if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; - if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; - if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'cancel', "taskID=$task->id", $lang->task->buttonCancel))) echo $lang->task->buttonCancel . ' '; - if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; - if(!common::printLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", $lang->task->assign)) echo $lang->task->assign . ' '; - if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; - if(common::hasPriv('task', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!common::printLink('task', 'delete',"projectID=$task->project&taskID=$task->id", $lang->task->buttonDelete, 'hiddenwin')) echo $lang->task->buttonDelete . ' '; - } - echo html::a($browseLink, $lang->goback); - ?> -
          -
          - - - - - - - -
          -
          - task->legendDesc;?> -
          desc;?>
          -
          - fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true'));?> - -
          - deleted) - { - if(!(($task->status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; - if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; - if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; - if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'cancel', "taskID=$task->id", $lang->task->buttonCancel))) echo $lang->task->buttonCancel . ' '; - if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; - if(!common::printLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", $lang->task->assign)) echo $lang->task->assign . ' '; - if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; - if(common::hasPriv('task', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - if(!common::printLink('task', 'delete',"projectID=$task->project&taskID=$task->id", $lang->task->buttonDelete, 'hiddenwin')) echo $lang->task->buttonDelete . ' '; - } - echo html::a($browseLink, $lang->goback); - ?> -
          - -
          -
          - task->legendBasic;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          task->project;?>project", $project->name)) echo $project->name;?>
          task->story;?> - storyTitle and !common::printLink('story', 'view', "storyID=$task->story", $task->storyTitle)) echo $task->storyTitle; - if($task->needConfirm) - { - echo "({$lang->story->changed} "; - echo html::a($this->createLink('task', 'confirmStoryChange', "taskID=$task->id"), $lang->confirm, 'hiddenwin'); - echo ")"; - } - ?> -
          task->assignedTo;?>assignedToRealName . $lang->at . $task->assignedDate;?>
          task->type;?>task->typeList[$task->type];?>
          task->status;?>show($lang->task->statusList, $task->status);?>
          task->pri;?>show($lang->task->priList, $task->pri);?>
          task->mailto;?>mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
          -
          -
          - task->legendEffort;?> - - - - - - - - - - - - - - - - - -
          task->deadline;?> - deadline; - if(isset($task->delay)) printf($lang->task->delayWarning, $task->delay); - ?> -
          task->estimate;?>estimate . $lang->workingHour;?>
          task->consumed;?>consumed . $lang->workingHour;?>
          task->left;?>left . $lang->workingHour;?>
          -
          -
          - task->legendLife;?> - - - - - - - - - - - - - - - - - - - - - - - - - -
          task->openedBy;?>openedBy) echo $users[$task->openedBy] . $lang->at . $task->openedDate;?>
          task->finishedBy;?>finishedBy) echo $users[$task->finishedBy] . $lang->at . $task->finishedDate;?>
          task->canceledBy;?>canceledBy) echo $users[$task->canceledBy] . $lang->at . $task->canceledDate;?>
          task->closedBy;?>closedBy) echo $users[$task->closedBy] . $lang->at . $task->closedDate;?>
          task->closedReason;?>task->reasonList[$task->closedReason];?>
          task->lastEdited;?>lastEditedBy) echo $users[$task->lastEditedBy] . $lang->at . $task->lastEditedDate;?>
          -
          -
          - + + * @package task + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +fromBug == 0):?> +
          '>TASK #id . $lang->colon . $task->name;?>
          + +
          '>TASK #id . $lang->colon . $task->name . '('. $lang->task->fromBug . $lang->colon . $task->fromBug . ')';?>
          + +
          + session->taskList != false ? $app->session->taskList : $this->createLink('project', 'browse', "projectID=$task->project"); + if(!$task->deleted) + { + //if(!($task->status != 'closed' and $task->status != 'cancel' and common::printLink('task', 'logEfforts', "taskID=$task->id", $lang->task->buttonLogEfforts))) echo $lang->task->buttonLogEfforts . ' '; + if(!(($task->status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; + if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; + if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; + if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'cancel', "taskID=$task->id", $lang->task->buttonCancel))) echo $lang->task->buttonCancel . ' '; + if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; + if(!common::printLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", $lang->task->assign)) echo $lang->task->assign . ' '; + if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; + if(common::hasPriv('task', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!common::printLink('task', 'delete',"projectID=$task->project&taskID=$task->id", $lang->task->buttonDelete, 'hiddenwin')) echo $lang->task->buttonDelete . ' '; + } + echo html::a($browseLink, $lang->goback); + ?> +
          +
          + + + + + + + +
          +
          + task->legendDesc;?> +
          desc;?>
          +
          + fetch('file', 'printFiles', array('files' => $task->files, 'fieldset' => 'true'));?> + +
          + deleted) + { + if(!(($task->status == 'wait') and common::printLink('task', 'start', "taskID=$task->id", $lang->task->buttonStart))) echo $lang->task->buttonStart . ' '; + if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'finish', "taskID=$task->id", $lang->task->buttonDone))) echo $lang->task->buttonDone . ' '; + if(!(($task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'close', "taskID=$task->id", $lang->task->buttonClose))) echo $lang->task->buttonClose . ' '; + if(!(($task->status == 'wait' or $task->status == 'doing') and common::printLink('task', 'cancel', "taskID=$task->id", $lang->task->buttonCancel))) echo $lang->task->buttonCancel . ' '; + if(!(($task->status == 'closed' or $task->status == 'done' or $task->status == 'cancel') and common::printLink('task', 'activate', "taskID=$task->id", $lang->task->buttonActivate))) echo $lang->task->buttonActivate . ' '; + if(!common::printLink('task', 'assignTo', "projectID=$task->project&taskID=$task->id", $lang->task->assign)) echo $lang->task->assign . ' '; + if(!common::printLink('task', 'edit', "taskID=$task->id", $lang->task->buttonEdit)) echo $lang->task->buttonEdit . ' '; + if(common::hasPriv('task', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + if(!common::printLink('task', 'delete',"projectID=$task->project&taskID=$task->id", $lang->task->buttonDelete, 'hiddenwin')) echo $lang->task->buttonDelete . ' '; + } + echo html::a($browseLink, $lang->goback); + ?> +
          + +
          +
          + task->legendBasic;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          task->project;?>project", $project->name)) echo $project->name;?>
          task->story;?> + storyTitle and !common::printLink('story', 'view', "storyID=$task->story", $task->storyTitle)) echo $task->storyTitle; + if($task->needConfirm) + { + echo "({$lang->story->changed} "; + echo html::a($this->createLink('task', 'confirmStoryChange', "taskID=$task->id"), $lang->confirm, 'hiddenwin'); + echo ")"; + } + ?> +
          task->assignedTo;?>assignedToRealName . $lang->at . $task->assignedDate;?>
          task->type;?>task->typeList[$task->type];?>
          task->status;?>show($lang->task->statusList, $task->status);?>
          task->pri;?>show($lang->task->priList, $task->pri);?>
          task->mailto;?>mailto)); foreach($mailto as $account) echo ' ' . $users[$account]; ?>
          +
          +
          + task->legendEffort;?> + + + + + + + + + + + + + + + + + +
          task->deadline;?> + deadline; + if(isset($task->delay)) printf($lang->task->delayWarning, $task->delay); + ?> +
          task->estimate;?>estimate . $lang->workingHour;?>
          task->consumed;?>consumed . $lang->workingHour;?>
          task->left;?>left . $lang->workingHour;?>
          +
          +
          + task->legendLife;?> + + + + + + + + + + + + + + + + + + + + + + + + + +
          task->openedBy;?>openedBy) echo $users[$task->openedBy] . $lang->at . $task->openedDate;?>
          task->finishedBy;?>finishedBy) echo $users[$task->finishedBy] . $lang->at . $task->finishedDate;?>
          task->canceledBy;?>canceledBy) echo $users[$task->canceledBy] . $lang->at . $task->canceledDate;?>
          task->closedBy;?>closedBy) echo $users[$task->closedBy] . $lang->at . $task->closedDate;?>
          task->closedReason;?>task->reasonList[$task->closedReason];?>
          task->lastEdited;?>lastEditedBy) echo $users[$task->lastEditedBy] . $lang->at . $task->lastEditedDate;?>
          +
          +
          + diff --git a/module/testcase/control.php b/module/testcase/control.php index 94a3c1366a..a4ceec8e8b 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -1,550 +1,550 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -class testcase extends control -{ - private $products = array(); - - /** - * Construct function, load product, tree, user auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('product'); - $this->loadModel('tree'); - $this->loadModel('user'); - $this->view->products = $this->products = $this->product->getPairs(); - } - - /** - * Index page. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('testcase', 'browse')); - } - - /** - * Browse cases. - * - * @param int $productID - * @param string $browseType - * @param int $param - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Set browseType, productID, moduleID and queryID. */ - $browseType = strtolower($browseType); - $productID = $this->product->saveState($productID, $this->products); - $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; - $queryID = ($browseType == 'bysearch') ? (int)$param : 0; - - /* Set menu, save session. */ - $this->testcase->setMenu($this->products, $productID); - $this->session->set('caseList', $this->app->getURI(true)); - $this->session->set('productID', $productID); - $this->session->set('moduleID', $moduleID); - $this->session->set('browseType', $browseType); - $this->session->set('orderBy', $orderBy); - - /* Load lang. */ - $this->app->loadLang('testtask'); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - /* By module or all cases. */ - if($browseType == 'bymodule' or $browseType == 'all') - { - $childModuleIds = $this->tree->getAllChildId($moduleID); - $this->view->cases = $this->testcase->getModuleCases($productID, $childModuleIds, $orderBy, $pager); - } - /* Cases need confirmed. */ - elseif($browseType == 'needconfirm') - { - $this->view->cases = $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_CASE)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') - ->where("t2.status = 'active'") - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t2.version > t1.storyVersion') - ->orderBy($orderBy) - ->fetchAll(); - } - /* By search. */ - elseif($browseType == 'bysearch') - { - if($queryID) - { - $query = $this->loadModel('search')->getQuery($queryID); - if($query) - { - $this->session->set('testcaseQuery', $query->sql); - $this->session->set('testcaseForm', $query->form); - } - else - { - $this->session->set('testcaseQuery', ' 1 = 1'); - } - } - else - { - if($this->session->testcaseQuery == false) $this->session->set('testcaseQuery', ' 1 = 1'); - } - - $caseQuery = str_replace("`product` = 'all'", '1', $this->session->testcaseQuery); // If product is all, change it to 1=1. - $this->view->cases = $this->dao->select('*')->from(TABLE_CASE)->where($caseQuery) - ->andWhere('product')->eq($productID) - ->andWhere('deleted')->eq(0) - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /* save session .*/ - $sql = $this->dao->get(); - $sql = explode('WHERE', $sql); - $sql = explode('ORDER', $sql[1]); - $this->session->set('testcaseReport', $sql[0]); - - /* Build the search form. */ - $this->config->testcase->search['params']['product']['values']= array($productID => $this->products[$productID], 'all' => $this->lang->testcase->allProduct); - $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case'); - $this->config->testcase->search['actionURL'] = $this->createLink('testcase', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); - $this->config->testcase->search['queryID'] = $queryID; - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->testcase->search); - - /* Assign. */ - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->common; - $this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testcase->common; - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'case', $startModuleID = 0, array('treeModel', 'createCaseLink')); - $this->view->moduleID = $moduleID; - $this->view->pager = $pager; - $this->view->users = $this->user->getPairs('noletter'); - $this->view->orderBy = $orderBy; - $this->view->browseType = $browseType; - $this->view->param = $param; - $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; - - $this->display(); - } - - /** - * Create a test case. - * - * @param int $productID - * @param int $moduleID - * @param string $from - * @param int $param - * @access public - * @return void - */ - public function create($productID, $moduleID = 0, $from = '', $param = 0, $storyID = 0) - { - $testcaseID = $from == 'testcase' ? $param : 0; - $bugID = $from == 'bug' ? $param : 0; - - $this->loadModel('story'); - if(!empty($_POST)) - { - $caseID = $this->testcase->create($bugID); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action'); - $this->action->create('case', $caseID, 'Opened'); - die(js::locate($this->createLink('testcase', 'browse', "productID=$_POST[product]&browseType=byModule¶m=$_POST[module]"), 'parent')); - } - if(empty($this->products)) $this->locate($this->createLink('product', 'create')); - - /* Set productID and currentModuleID. */ - $productID = $this->product->saveState($productID, $this->products); - $currentModuleID = (int)$moduleID; - - /* Set menu. */ - $this->testcase->setMenu($this->products, $productID); - - /* Init vars. */ - $type = 'feature'; - $stage = ''; - $pri = 0; - $title = ''; - $precondition = ''; - $keywords = ''; - $steps = array(); - - /* If testcaseID large than 0, use this testcase as template. */ - if($testcaseID > 0) - { - $testcase = $this->testcase->getById($testcaseID); - $productID = $testcase->product; - $type = $testcase->type ? $testcase->type : 'feature'; - $stage = $testcase->stage; - $pri = $testcase->pri; - $storyID = $testcase->story; - $title = $testcase->title; - $precondition = $testcase->precondition; - $keywords = $testcase->keywords; - $steps = $testcase->steps; - } - - /* If bugID large than 0, use this bug as template. */ - if($bugID > 0) - { - $bug = $this->loadModel('bug')->getById($bugID); - $type = $bug->type; - $pri = $bug->pri ? $bug->pri : $bug->severity; - $storyID = $bug->story; - $title = $bug->title; - $keywords = $bug->keywords; - $steps = $this->testcase->createStepsFromBug($bug->steps); - } - - /* Padding the steps to the default steps count. */ - if(count($steps) < $this->config->testcase->defaultSteps) - { - $paddingCount = $this->config->testcase->defaultSteps - count($steps); - $step->desc = ''; - $step->expect = ''; - for($i = 1; $i <= $paddingCount; $i ++) $steps[] = $step; - } - - $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->create; - $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); - $position[] = $this->lang->testcase->create; - - $users = $this->user->getPairs(); - $this->view->header = $header; - $this->view->position = $position; - $this->view->productID = $productID; - $this->view->users = $users; - $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); - $this->view->currentModuleID = $currentModuleID; - $this->view->stories = $this->story->getProductStoryPairs($productID); - $this->view->type = $type; - $this->view->stage = $stage; - $this->view->pri = $pri; - $this->view->storyID = $storyID; - $this->view->title = $title; - $this->view->precondition = $precondition; - $this->view->keywords = $keywords; - $this->view->steps = $steps; - - $this->display(); - } - - - /** - * Create a batch test case. - * - * @param int $productID - * @param int $moduleID - * @param int $testcaseID - * @access public - * @return void - */ - public function batchCreate($productID, $moduleID = 0) - { - $this->loadModel('story'); - if(!empty($_POST)) - { - $caseID = $this->testcase->batchCreate($productID); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('testcase', 'browse', "productID=$_POST[product]&browseType=byModule¶m=$_POST[module]"), 'parent')); - } - if(empty($this->products)) $this->locate($this->createLink('product', 'create')); - - /* Set productID and currentModuleID. */ - $productID = $this->product->saveState($productID, $this->products); - $currentModuleID = (int)$moduleID; - - /* Set menu. */ - $this->testcase->setMenu($this->products, $productID); - - /* Init vars. */ - $type = 'feature'; - $title = ''; - - $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->batchCreate; - $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); - $position[] = $this->lang->testcase->batchCreate; - - $users = $this->user->getPairs(); - $this->view->header = $header; - $this->view->position = $position; - $this->view->productID = $productID; - $this->view->users = $users; - $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); - $this->view->currentModuleID = $currentModuleID; - $this->view->stories = $this->story->getProductStoryPairs($productID); - $this->view->type = $type; - $this->view->title = $title; - - $this->display(); - } - - /** - * View a test case. - * - * @param int $caseID - * @param int $version - * @access public - * @return void - */ - public function view($caseID, $version = 0) - { - $case = $this->testcase->getById($caseID, $version); - if(!$case) die(js::error($this->lang->notFound) . js::locate('back')); - - $productID = $case->product; - $this->testcase->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->view; - $this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testcase->view; - - $this->view->case = $case; - $this->view->productName = $this->products[$productID]; - $this->view->modulePath = $this->tree->getParents($case->module); - $this->view->users = $this->user->getPairs('noletter'); - $this->view->actions = $this->loadModel('action')->getList('case', $caseID); - - $this->display(); - } - - /** - * Edit a case. - * - * @param int $caseID - * @access public - * @return void - */ - public function edit($caseID, $comment = false) - { - $this->loadModel('story'); - - if(!empty($_POST)) - { - $changes = array(); - $files = array(); - if($comment == false) - { - $changes = $this->testcase->update($caseID); - if(dao::isError()) die(js::error(dao::getError())); - $files = $this->loadModel('file')->saveUpload('testcase', $caseID); - } - if($this->post->comment != '' or !empty($changes) or !empty($files)) - { - $this->loadModel('action'); - $action = !empty($changes) ? 'Edited' : 'Commented'; - $fileAction = ''; - if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n"; - $actionID = $this->action->create('case', $caseID, $action, $fileAction . $this->post->comment); - $this->action->logHistory($actionID, $changes); - } - die(js::locate($this->createLink('testcase', 'view', "caseID=$caseID"), 'parent')); - } - - $case = $this->testcase->getById($caseID); - if(empty($case->steps)) - { - $step->desc = ''; - $step->expect = ''; - $case->steps[] = $step; - } - $productID = $case->product; - $currentModuleID = $case->module; - $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->edit; - $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); - $position[] = $this->lang->testcase->edit; - - /* Set menu. */ - $this->testcase->setMenu($this->products, $productID); - - $users = $this->user->getPairs(); - $this->view->header = $header; - $this->view->position = $position; - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); - $this->view->currentModuleID = $currentModuleID; - $this->view->users = $users; - $this->view->stories = $this->story->getProductStoryPairs($productID); - - $this->view->header = $header; - $this->view->position = $position; - $this->view->case = $case; - $this->view->actions = $this->loadModel('action')->getList('case', $caseID); - - $this->display(); - } - - /** - * Delete a test case - * - * @param int $caseID - * @param string $confirm yes|noe - * @access public - * @return void - */ - public function delete($caseID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->testcase->confirmDelete, inlink('delete', "caseID=$caseID&confirm=yes"))); - } - else - { - $this->testcase->delete(TABLE_CASE, $caseID); - die(js::locate($this->session->caseList, 'parent')); - } - } - - /** - * Confirm story changes. - * - * @param int $caseID - * @access public - * @return void - */ - public function confirmStoryChange($caseID) - { - $case = $this->testcase->getById($caseID); - $this->dao->update(TABLE_CASE)->set('storyVersion')->eq($case->latestStoryVersion)->where('id')->eq($caseID)->exec(); - $this->loadModel('action')->create('case', $caseID, 'confirmed', '', $case->latestStoryVersion); - die(js::reload('parent')); - } - - /** - * export - * - * @param string $productID - * @param string $orderBy - * @access public - * @return void - */ - public function export($productID, $orderBy) - { - if($_POST) - { - $caseLang = $this->lang->testcase; - $caseConfig = $this->config->testcase; - - /* Create field lists. */ - $fields = explode(',', $caseConfig->exportFields); - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($caseLang->$fieldName) ? $caseLang->$fieldName : $fieldName; - unset($fields[$key]); - } - - /* Get cases. */ - $cases = $this->dao->select('*')->from(TABLE_CASE)->alias('t1')->where($this->session->testcaseReport)->orderBy($orderBy)->fetchAll('id'); - - /* Get users, products and projects. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $products = $this->loadModel('product')->getPairs(); - - /* Get related objects id lists. */ - $relatedModuleIdList = array(); - $relatedStoryIdList = array(); - $relatedCaseIdList = array(); - - foreach($cases as $case) - { - $relatedModuleIdList[$case->module] = $case->module; - $relatedStoryIdList[$case->story] = $case->story; - $relatedCaseIdList[$case->linkCase] = $case->linkCase; - - /* Process link cases. */ - $linkCases = explode(',', $case->linkCase); - foreach($linkCases as $linkCaseID) - { - if($linkCaseID) $relatedCaseIdList[$linkCaseID] = trim($linkCaseID); - } - } - - /* Get related objects title or names. */ - $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); - $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); - $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); - $relatedSteps = $this->dao->select('`case`, version, `desc`, expect')->from(TABLE_CASESTEP)->where('`case`')->in(@array_keys($cases))->orderBy('version desc,id')->fetchGroup('case'); - - foreach($cases as $case) - { - $case->steps = ''; - if(isset($relatedSteps[$case->id])) - { - $i = 1; - foreach($relatedSteps[$case->id] as $step) - { - $case->steps .= $i . ":" . $step->desc . '
          ' . $caseLang->stepExpect . ':' . $step->expect . '
          '; - $i ++; - if($step->version != $case->version) break; - } - } - - if($this->post->fileType == 'csv') - { - $case->steps = str_replace('
          ', "\n", $case->steps); - $case->steps = str_replace('"', '""', $case->steps); - } - - /* fill some field with useful value. */ - if(isset($products[$case->product])) $case->product = $products[$case->product]; - if(isset($relatedModules[$case->module])) $case->module = $relatedModules[$case->module]; - if(isset($relatedStories[$case->story])) $case->story = $relatedStories[$case->story]; - - if(isset($caseLang->priList[$case->pri])) $case->pri = $caseLang->priList[$case->pri]; - if(isset($caseLang->typeList[$case->type])) $case->type = $caseLang->typeList[$case->type]; - if(isset($caseLang->stageList[$case->stage])) $case->stage = $caseLang->stageList[$case->stage]; - if(isset($caseLang->statusList[$case->status])) $case->status = $caseLang->statusList[$case->status]; - if(isset($users[$case->openedBy])) $case->openedBy = $users[$case->openedBy]; - if(isset($users[$case->lastEditedBy])) $case->lastEditedBy = $users[$case->lastEditedBy]; - - $case->openedDate = substr($case->openedDate, 0, 10); - $case->lastEditedDate = substr($case->lastEditedDate, 0, 10); - - if($case->linkCase) - { - $tmpLinkCases = array(); - $linkCaseIdList = explode(',', $case->linkCase); - foreach($linkCaseIdList as $linkCaseID) - { - $linkCaseID = trim($linkCaseID); - $tmpLinkCases[] = isset($relatedCases[$linkCaseID]) ? $relatedCases[$linkCaseID] : $linkCaseID; - } - $case->linkCase = join("; \n", $tmpLinkCases); - } - } - - $this->post->set('fields', $fields); - $this->post->set('rows', $cases); - $this->fetch('file', 'export2' . $this->post->fileType, $_POST); - } - - $this->display(); - } -} + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +class testcase extends control +{ + private $products = array(); + + /** + * Construct function, load product, tree, user auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('product'); + $this->loadModel('tree'); + $this->loadModel('user'); + $this->view->products = $this->products = $this->product->getPairs(); + } + + /** + * Index page. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('testcase', 'browse')); + } + + /** + * Browse cases. + * + * @param int $productID + * @param string $browseType + * @param int $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($productID = 0, $browseType = 'byModule', $param = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Set browseType, productID, moduleID and queryID. */ + $browseType = strtolower($browseType); + $productID = $this->product->saveState($productID, $this->products); + $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; + $queryID = ($browseType == 'bysearch') ? (int)$param : 0; + + /* Set menu, save session. */ + $this->testcase->setMenu($this->products, $productID); + $this->session->set('caseList', $this->app->getURI(true)); + $this->session->set('productID', $productID); + $this->session->set('moduleID', $moduleID); + $this->session->set('browseType', $browseType); + $this->session->set('orderBy', $orderBy); + + /* Load lang. */ + $this->app->loadLang('testtask'); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + /* By module or all cases. */ + if($browseType == 'bymodule' or $browseType == 'all') + { + $childModuleIds = $this->tree->getAllChildId($moduleID); + $this->view->cases = $this->testcase->getModuleCases($productID, $childModuleIds, $orderBy, $pager); + } + /* Cases need confirmed. */ + elseif($browseType == 'needconfirm') + { + $this->view->cases = $this->dao->select('t1.*, t2.title AS storyTitle')->from(TABLE_CASE)->alias('t1')->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id') + ->where("t2.status = 'active'") + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.version > t1.storyVersion') + ->orderBy($orderBy) + ->fetchAll(); + } + /* By search. */ + elseif($browseType == 'bysearch') + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('testcaseQuery', $query->sql); + $this->session->set('testcaseForm', $query->form); + } + else + { + $this->session->set('testcaseQuery', ' 1 = 1'); + } + } + else + { + if($this->session->testcaseQuery == false) $this->session->set('testcaseQuery', ' 1 = 1'); + } + + $caseQuery = str_replace("`product` = 'all'", '1', $this->session->testcaseQuery); // If product is all, change it to 1=1. + $this->view->cases = $this->dao->select('*')->from(TABLE_CASE)->where($caseQuery) + ->andWhere('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /* save session .*/ + $sql = $this->dao->get(); + $sql = explode('WHERE', $sql); + $sql = explode('ORDER', $sql[1]); + $this->session->set('testcaseReport', $sql[0]); + + /* Build the search form. */ + $this->config->testcase->search['params']['product']['values']= array($productID => $this->products[$productID], 'all' => $this->lang->testcase->allProduct); + $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case'); + $this->config->testcase->search['actionURL'] = $this->createLink('testcase', 'browse', "productID=$productID&browseType=bySearch&queryID=myQueryID"); + $this->config->testcase->search['queryID'] = $queryID; + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->testcase->search); + + /* Assign. */ + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->common; + $this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testcase->common; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleTree = $this->tree->getTreeMenu($productID, $viewType = 'case', $startModuleID = 0, array('treeModel', 'createCaseLink')); + $this->view->moduleID = $moduleID; + $this->view->pager = $pager; + $this->view->users = $this->user->getPairs('noletter'); + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + $this->view->param = $param; + $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; + + $this->display(); + } + + /** + * Create a test case. + * + * @param int $productID + * @param int $moduleID + * @param string $from + * @param int $param + * @access public + * @return void + */ + public function create($productID, $moduleID = 0, $from = '', $param = 0, $storyID = 0) + { + $testcaseID = $from == 'testcase' ? $param : 0; + $bugID = $from == 'bug' ? $param : 0; + + $this->loadModel('story'); + if(!empty($_POST)) + { + $caseID = $this->testcase->create($bugID); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action'); + $this->action->create('case', $caseID, 'Opened'); + die(js::locate($this->createLink('testcase', 'browse', "productID=$_POST[product]&browseType=byModule¶m=$_POST[module]"), 'parent')); + } + if(empty($this->products)) $this->locate($this->createLink('product', 'create')); + + /* Set productID and currentModuleID. */ + $productID = $this->product->saveState($productID, $this->products); + $currentModuleID = (int)$moduleID; + + /* Set menu. */ + $this->testcase->setMenu($this->products, $productID); + + /* Init vars. */ + $type = 'feature'; + $stage = ''; + $pri = 0; + $title = ''; + $precondition = ''; + $keywords = ''; + $steps = array(); + + /* If testcaseID large than 0, use this testcase as template. */ + if($testcaseID > 0) + { + $testcase = $this->testcase->getById($testcaseID); + $productID = $testcase->product; + $type = $testcase->type ? $testcase->type : 'feature'; + $stage = $testcase->stage; + $pri = $testcase->pri; + $storyID = $testcase->story; + $title = $testcase->title; + $precondition = $testcase->precondition; + $keywords = $testcase->keywords; + $steps = $testcase->steps; + } + + /* If bugID large than 0, use this bug as template. */ + if($bugID > 0) + { + $bug = $this->loadModel('bug')->getById($bugID); + $type = $bug->type; + $pri = $bug->pri ? $bug->pri : $bug->severity; + $storyID = $bug->story; + $title = $bug->title; + $keywords = $bug->keywords; + $steps = $this->testcase->createStepsFromBug($bug->steps); + } + + /* Padding the steps to the default steps count. */ + if(count($steps) < $this->config->testcase->defaultSteps) + { + $paddingCount = $this->config->testcase->defaultSteps - count($steps); + $step->desc = ''; + $step->expect = ''; + for($i = 1; $i <= $paddingCount; $i ++) $steps[] = $step; + } + + $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->create; + $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); + $position[] = $this->lang->testcase->create; + + $users = $this->user->getPairs(); + $this->view->header = $header; + $this->view->position = $position; + $this->view->productID = $productID; + $this->view->users = $users; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); + $this->view->currentModuleID = $currentModuleID; + $this->view->stories = $this->story->getProductStoryPairs($productID); + $this->view->type = $type; + $this->view->stage = $stage; + $this->view->pri = $pri; + $this->view->storyID = $storyID; + $this->view->title = $title; + $this->view->precondition = $precondition; + $this->view->keywords = $keywords; + $this->view->steps = $steps; + + $this->display(); + } + + + /** + * Create a batch test case. + * + * @param int $productID + * @param int $moduleID + * @param int $testcaseID + * @access public + * @return void + */ + public function batchCreate($productID, $moduleID = 0) + { + $this->loadModel('story'); + if(!empty($_POST)) + { + $caseID = $this->testcase->batchCreate($productID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('testcase', 'browse', "productID=$_POST[product]&browseType=byModule¶m=$_POST[module]"), 'parent')); + } + if(empty($this->products)) $this->locate($this->createLink('product', 'create')); + + /* Set productID and currentModuleID. */ + $productID = $this->product->saveState($productID, $this->products); + $currentModuleID = (int)$moduleID; + + /* Set menu. */ + $this->testcase->setMenu($this->products, $productID); + + /* Init vars. */ + $type = 'feature'; + $title = ''; + + $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->batchCreate; + $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); + $position[] = $this->lang->testcase->batchCreate; + + $users = $this->user->getPairs(); + $this->view->header = $header; + $this->view->position = $position; + $this->view->productID = $productID; + $this->view->users = $users; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); + $this->view->currentModuleID = $currentModuleID; + $this->view->stories = $this->story->getProductStoryPairs($productID); + $this->view->type = $type; + $this->view->title = $title; + + $this->display(); + } + + /** + * View a test case. + * + * @param int $caseID + * @param int $version + * @access public + * @return void + */ + public function view($caseID, $version = 0) + { + $case = $this->testcase->getById($caseID, $version); + if(!$case) die(js::error($this->lang->notFound) . js::locate('back')); + + $productID = $case->product; + $this->testcase->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->view; + $this->view->position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testcase->view; + + $this->view->case = $case; + $this->view->productName = $this->products[$productID]; + $this->view->modulePath = $this->tree->getParents($case->module); + $this->view->users = $this->user->getPairs('noletter'); + $this->view->actions = $this->loadModel('action')->getList('case', $caseID); + + $this->display(); + } + + /** + * Edit a case. + * + * @param int $caseID + * @access public + * @return void + */ + public function edit($caseID, $comment = false) + { + $this->loadModel('story'); + + if(!empty($_POST)) + { + $changes = array(); + $files = array(); + if($comment == false) + { + $changes = $this->testcase->update($caseID); + if(dao::isError()) die(js::error(dao::getError())); + $files = $this->loadModel('file')->saveUpload('testcase', $caseID); + } + if($this->post->comment != '' or !empty($changes) or !empty($files)) + { + $this->loadModel('action'); + $action = !empty($changes) ? 'Edited' : 'Commented'; + $fileAction = ''; + if(!empty($files)) $fileAction = $this->lang->addFiles . join(',', $files) . "\n"; + $actionID = $this->action->create('case', $caseID, $action, $fileAction . $this->post->comment); + $this->action->logHistory($actionID, $changes); + } + die(js::locate($this->createLink('testcase', 'view', "caseID=$caseID"), 'parent')); + } + + $case = $this->testcase->getById($caseID); + if(empty($case->steps)) + { + $step->desc = ''; + $step->expect = ''; + $case->steps[] = $step; + } + $productID = $case->product; + $currentModuleID = $case->module; + $header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testcase->edit; + $position[] = html::a($this->createLink('testcase', 'browse', "productID=$productID"), $this->products[$productID]); + $position[] = $this->lang->testcase->edit; + + /* Set menu. */ + $this->testcase->setMenu($this->products, $productID); + + $users = $this->user->getPairs(); + $this->view->header = $header; + $this->view->position = $position; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->moduleOptionMenu = $this->tree->getOptionMenu($productID, $viewType = 'case', $startModuleID = 0); + $this->view->currentModuleID = $currentModuleID; + $this->view->users = $users; + $this->view->stories = $this->story->getProductStoryPairs($productID); + + $this->view->header = $header; + $this->view->position = $position; + $this->view->case = $case; + $this->view->actions = $this->loadModel('action')->getList('case', $caseID); + + $this->display(); + } + + /** + * Delete a test case + * + * @param int $caseID + * @param string $confirm yes|noe + * @access public + * @return void + */ + public function delete($caseID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->testcase->confirmDelete, inlink('delete', "caseID=$caseID&confirm=yes"))); + } + else + { + $this->testcase->delete(TABLE_CASE, $caseID); + die(js::locate($this->session->caseList, 'parent')); + } + } + + /** + * Confirm story changes. + * + * @param int $caseID + * @access public + * @return void + */ + public function confirmStoryChange($caseID) + { + $case = $this->testcase->getById($caseID); + $this->dao->update(TABLE_CASE)->set('storyVersion')->eq($case->latestStoryVersion)->where('id')->eq($caseID)->exec(); + $this->loadModel('action')->create('case', $caseID, 'confirmed', '', $case->latestStoryVersion); + die(js::reload('parent')); + } + + /** + * export + * + * @param string $productID + * @param string $orderBy + * @access public + * @return void + */ + public function export($productID, $orderBy) + { + if($_POST) + { + $caseLang = $this->lang->testcase; + $caseConfig = $this->config->testcase; + + /* Create field lists. */ + $fields = explode(',', $caseConfig->exportFields); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($caseLang->$fieldName) ? $caseLang->$fieldName : $fieldName; + unset($fields[$key]); + } + + /* Get cases. */ + $cases = $this->dao->select('*')->from(TABLE_CASE)->alias('t1')->where($this->session->testcaseReport)->orderBy($orderBy)->fetchAll('id'); + + /* Get users, products and projects. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $products = $this->loadModel('product')->getPairs(); + + /* Get related objects id lists. */ + $relatedModuleIdList = array(); + $relatedStoryIdList = array(); + $relatedCaseIdList = array(); + + foreach($cases as $case) + { + $relatedModuleIdList[$case->module] = $case->module; + $relatedStoryIdList[$case->story] = $case->story; + $relatedCaseIdList[$case->linkCase] = $case->linkCase; + + /* Process link cases. */ + $linkCases = explode(',', $case->linkCase); + foreach($linkCases as $linkCaseID) + { + if($linkCaseID) $relatedCaseIdList[$linkCaseID] = trim($linkCaseID); + } + } + + /* Get related objects title or names. */ + $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); + $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); + $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); + $relatedSteps = $this->dao->select('`case`, version, `desc`, expect')->from(TABLE_CASESTEP)->where('`case`')->in(@array_keys($cases))->orderBy('version desc,id')->fetchGroup('case'); + + foreach($cases as $case) + { + $case->steps = ''; + if(isset($relatedSteps[$case->id])) + { + $i = 1; + foreach($relatedSteps[$case->id] as $step) + { + $case->steps .= $i . ":" . $step->desc . '
          ' . $caseLang->stepExpect . ':' . $step->expect . '
          '; + $i ++; + if($step->version != $case->version) break; + } + } + + if($this->post->fileType == 'csv') + { + $case->steps = str_replace('
          ', "\n", $case->steps); + $case->steps = str_replace('"', '""', $case->steps); + } + + /* fill some field with useful value. */ + if(isset($products[$case->product])) $case->product = $products[$case->product]; + if(isset($relatedModules[$case->module])) $case->module = $relatedModules[$case->module]; + if(isset($relatedStories[$case->story])) $case->story = $relatedStories[$case->story]; + + if(isset($caseLang->priList[$case->pri])) $case->pri = $caseLang->priList[$case->pri]; + if(isset($caseLang->typeList[$case->type])) $case->type = $caseLang->typeList[$case->type]; + if(isset($caseLang->stageList[$case->stage])) $case->stage = $caseLang->stageList[$case->stage]; + if(isset($caseLang->statusList[$case->status])) $case->status = $caseLang->statusList[$case->status]; + if(isset($users[$case->openedBy])) $case->openedBy = $users[$case->openedBy]; + if(isset($users[$case->lastEditedBy])) $case->lastEditedBy = $users[$case->lastEditedBy]; + + $case->openedDate = substr($case->openedDate, 0, 10); + $case->lastEditedDate = substr($case->lastEditedDate, 0, 10); + + if($case->linkCase) + { + $tmpLinkCases = array(); + $linkCaseIdList = explode(',', $case->linkCase); + foreach($linkCaseIdList as $linkCaseID) + { + $linkCaseID = trim($linkCaseID); + $tmpLinkCases[] = isset($relatedCases[$linkCaseID]) ? $relatedCases[$linkCaseID] : $linkCaseID; + } + $case->linkCase = join("; \n", $tmpLinkCases); + } + } + + $this->post->set('fields', $fields); + $this->post->set('rows', $cases); + $this->fetch('file', 'export2' . $this->post->fileType, $_POST); + } + + $this->display(); + } +} diff --git a/module/testcase/lang/en.php b/module/testcase/lang/en.php index a4d77294b6..c88ad3b04e 100644 --- a/module/testcase/lang/en.php +++ b/module/testcase/lang/en.php @@ -1,135 +1,135 @@ - - * @package testcase - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->testcase->id = 'ID'; -$lang->testcase->product = 'Product'; -$lang->testcase->module = 'Module'; -$lang->testcase->story = 'Story'; -$lang->testcase->storyVersion = 'Story version'; -$lang->testcase->title = 'Title'; -$lang->testcase->precondition = 'precondition'; -$lang->testcase->pri = 'Priority'; -$lang->testcase->type = 'Type'; -$lang->testcase->status = 'Status'; -$lang->testcase->steps = 'Steps'; -$lang->testcase->frequency = 'Frequency'; -$lang->testcase->order = 'Order'; -$lang->testcase->openedBy = 'Opened by '; -$lang->testcase->openedDate = 'Opened date'; -$lang->testcase->lastEditedBy = 'Last edited by'; -$lang->testcase->lastEditedDate = 'Last edited date'; -$lang->testcase->version = 'Version'; -$lang->testcase->result = 'Result'; -$lang->testcase->real = 'Real'; -$lang->testcase->keywords = 'Keywords'; -$lang->testcase->files = 'Files'; -$lang->testcase->howRun = 'How run'; -$lang->testcase->scriptedBy = 'Scripted by'; -$lang->testcase->scriptedDate = 'Scripted date'; -$lang->testcase->scriptedStatus = 'Scripted status'; -$lang->testcase->scriptedLocation = 'Script location'; -$lang->testcase->linkCase = 'Related cases'; -$lang->testcase->stage = 'Stage'; -$lang->testcase->lastEditedByAB = 'Last edited by'; -$lang->testcase->lastEditedDateAB = 'Last edited date'; -$lang->testcase->allProduct = 'All product'; -$lang->case = $lang->testcase; // For dao checking using. Because 'case' is a php keywords, so the module name is testcase, table name is still case. - -$lang->testcase->stepID = 'ID'; -$lang->testcase->stepDesc = 'Step'; -$lang->testcase->stepExpect = 'Expect'; - -$lang->testcase->common = 'Case'; -$lang->testcase->index = "Index"; -$lang->testcase->create = "Create"; -$lang->testcase->batchCreate = "Batch create"; -$lang->testcase->delete = "Delete"; -$lang->testcase->view = "Info"; -$lang->testcase->edit = "Edit"; -$lang->testcase->delete = "Delete"; -$lang->testcase->browse = "Browse"; -$lang->testcase->export = "Export"; -$lang->testcase->confirmStoryChange = 'Confirm story change'; - -$lang->testcase->deleteStep = 'Delete'; -$lang->testcase->insertBefore = 'Insert before'; -$lang->testcase->insertAfter = 'Insert after'; - -$lang->testcase->selectProduct = 'Select product'; -$lang->testcase->byModule = 'By module'; -$lang->testcase->assignToMe = 'Cases to me'; -$lang->testcase->openedByMe = 'My Opened cases'; -$lang->testcase->allCases = 'All case'; -$lang->testcase->needConfirm = 'Story changed'; -$lang->testcase->moduleCases = 'By module'; -$lang->testcase->bySearch = 'By search'; -$lang->testcase->doneByMe = 'My runed cases'; - -$lang->testcase->lblProductAndModule = 'Product & module'; -$lang->testcase->lblTypeAndPri = 'Type & priority'; -$lang->testcase->lblSystemBrowserAndHardware = 'OS & browser'; -$lang->testcase->lblAssignAndMail = 'Assigned & mailto'; -$lang->testcase->lblStory = 'Story'; -$lang->testcase->lblLastEdited = 'Last edited'; - -$lang->testcase->legendRelated = 'Related info'; -$lang->testcase->legendBasicInfo = 'Basic info'; -$lang->testcase->legendMailto = 'Mailto'; -$lang->testcase->legendAttatch = 'Files'; -$lang->testcase->legendLinkBugs = 'Bug'; -$lang->testcase->legendOpenAndEdit = 'Open & edit'; -$lang->testcase->legendStoryAndTask = 'Story'; -$lang->testcase->legendCases = 'Related cases'; -$lang->testcase->legendSteps = 'Steps'; -$lang->testcase->legendAction = 'Action'; -$lang->testcase->legendHistory = 'History'; -$lang->testcase->legendComment = 'Comment'; -$lang->testcase->legendProduct = 'Product & module'; -$lang->testcase->legendVersion = 'Versions'; - -$lang->testcase->confirmDelete = 'Are you sure to delete this case?'; -$lang->testcase->same = 'The same as above'; -$lang->testcase->notes = '(Notes: the type and title must be written, otherwise it is no use)'; - -$lang->testcase->priList[3] = 3; -$lang->testcase->priList[1] = 1; -$lang->testcase->priList[2] = 2; -$lang->testcase->priList[4] = 4; - -/* Define the types. */ -$lang->testcase->typeList[''] = ''; -$lang->testcase->typeList['feature'] = 'Feature'; -$lang->testcase->typeList['performance'] = 'Performance'; -$lang->testcase->typeList['config'] = 'Config'; -$lang->testcase->typeList['install'] = 'Install'; -$lang->testcase->typeList['security'] = 'Security'; -$lang->testcase->typeList['other'] = 'Other'; - -$lang->testcase->stageList[''] = ''; -$lang->testcase->stageList['unittest'] = 'Unit testing'; -$lang->testcase->stageList['feature'] = 'Feature testing'; -$lang->testcase->stageList['intergrate'] = 'Integrate testing'; -$lang->testcase->stageList['system'] = 'System testing'; -$lang->testcase->stageList['smoke'] = 'Smoking testing'; -$lang->testcase->stageList['bvt'] = 'BVT testing'; - -$lang->testcase->statusList[''] = ''; -$lang->testcase->statusList['normal'] = 'Normal'; -$lang->testcase->statusList['blocked'] = 'Blocked'; -$lang->testcase->statusList['investigate'] = 'Investigate'; - -$lang->testcase->resultList['n/a'] = 'N/A'; -$lang->testcase->resultList['pass'] = 'Pass'; -$lang->testcase->resultList['fail'] = 'Fail'; -$lang->testcase->resultList['blocked'] = 'Blocked'; - -$lang->testcase->buttonEdit = 'Edit'; -$lang->testcase->buttonToList = 'Back'; + + * @package testcase + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->testcase->id = 'ID'; +$lang->testcase->product = 'Product'; +$lang->testcase->module = 'Module'; +$lang->testcase->story = 'Story'; +$lang->testcase->storyVersion = 'Story version'; +$lang->testcase->title = 'Title'; +$lang->testcase->precondition = 'precondition'; +$lang->testcase->pri = 'Priority'; +$lang->testcase->type = 'Type'; +$lang->testcase->status = 'Status'; +$lang->testcase->steps = 'Steps'; +$lang->testcase->frequency = 'Frequency'; +$lang->testcase->order = 'Order'; +$lang->testcase->openedBy = 'Opened by '; +$lang->testcase->openedDate = 'Opened date'; +$lang->testcase->lastEditedBy = 'Last edited by'; +$lang->testcase->lastEditedDate = 'Last edited date'; +$lang->testcase->version = 'Version'; +$lang->testcase->result = 'Result'; +$lang->testcase->real = 'Real'; +$lang->testcase->keywords = 'Keywords'; +$lang->testcase->files = 'Files'; +$lang->testcase->howRun = 'How run'; +$lang->testcase->scriptedBy = 'Scripted by'; +$lang->testcase->scriptedDate = 'Scripted date'; +$lang->testcase->scriptedStatus = 'Scripted status'; +$lang->testcase->scriptedLocation = 'Script location'; +$lang->testcase->linkCase = 'Related cases'; +$lang->testcase->stage = 'Stage'; +$lang->testcase->lastEditedByAB = 'Last edited by'; +$lang->testcase->lastEditedDateAB = 'Last edited date'; +$lang->testcase->allProduct = 'All product'; +$lang->case = $lang->testcase; // For dao checking using. Because 'case' is a php keywords, so the module name is testcase, table name is still case. + +$lang->testcase->stepID = 'ID'; +$lang->testcase->stepDesc = 'Step'; +$lang->testcase->stepExpect = 'Expect'; + +$lang->testcase->common = 'Case'; +$lang->testcase->index = "Index"; +$lang->testcase->create = "Create"; +$lang->testcase->batchCreate = "Batch create"; +$lang->testcase->delete = "Delete"; +$lang->testcase->view = "Info"; +$lang->testcase->edit = "Edit"; +$lang->testcase->delete = "Delete"; +$lang->testcase->browse = "Browse"; +$lang->testcase->export = "Export"; +$lang->testcase->confirmStoryChange = 'Confirm story change'; + +$lang->testcase->deleteStep = 'Delete'; +$lang->testcase->insertBefore = 'Insert before'; +$lang->testcase->insertAfter = 'Insert after'; + +$lang->testcase->selectProduct = 'Select product'; +$lang->testcase->byModule = 'By module'; +$lang->testcase->assignToMe = 'Cases to me'; +$lang->testcase->openedByMe = 'My Opened cases'; +$lang->testcase->allCases = 'All case'; +$lang->testcase->needConfirm = 'Story changed'; +$lang->testcase->moduleCases = 'By module'; +$lang->testcase->bySearch = 'By search'; +$lang->testcase->doneByMe = 'My runed cases'; + +$lang->testcase->lblProductAndModule = 'Product & module'; +$lang->testcase->lblTypeAndPri = 'Type & priority'; +$lang->testcase->lblSystemBrowserAndHardware = 'OS & browser'; +$lang->testcase->lblAssignAndMail = 'Assigned & mailto'; +$lang->testcase->lblStory = 'Story'; +$lang->testcase->lblLastEdited = 'Last edited'; + +$lang->testcase->legendRelated = 'Related info'; +$lang->testcase->legendBasicInfo = 'Basic info'; +$lang->testcase->legendMailto = 'Mailto'; +$lang->testcase->legendAttatch = 'Files'; +$lang->testcase->legendLinkBugs = 'Bug'; +$lang->testcase->legendOpenAndEdit = 'Open & edit'; +$lang->testcase->legendStoryAndTask = 'Story'; +$lang->testcase->legendCases = 'Related cases'; +$lang->testcase->legendSteps = 'Steps'; +$lang->testcase->legendAction = 'Action'; +$lang->testcase->legendHistory = 'History'; +$lang->testcase->legendComment = 'Comment'; +$lang->testcase->legendProduct = 'Product & module'; +$lang->testcase->legendVersion = 'Versions'; + +$lang->testcase->confirmDelete = 'Are you sure to delete this case?'; +$lang->testcase->same = 'The same as above'; +$lang->testcase->notes = '(Notes: the type and title must be written, otherwise it is no use)'; + +$lang->testcase->priList[3] = 3; +$lang->testcase->priList[1] = 1; +$lang->testcase->priList[2] = 2; +$lang->testcase->priList[4] = 4; + +/* Define the types. */ +$lang->testcase->typeList[''] = ''; +$lang->testcase->typeList['feature'] = 'Feature'; +$lang->testcase->typeList['performance'] = 'Performance'; +$lang->testcase->typeList['config'] = 'Config'; +$lang->testcase->typeList['install'] = 'Install'; +$lang->testcase->typeList['security'] = 'Security'; +$lang->testcase->typeList['other'] = 'Other'; + +$lang->testcase->stageList[''] = ''; +$lang->testcase->stageList['unittest'] = 'Unit testing'; +$lang->testcase->stageList['feature'] = 'Feature testing'; +$lang->testcase->stageList['intergrate'] = 'Integrate testing'; +$lang->testcase->stageList['system'] = 'System testing'; +$lang->testcase->stageList['smoke'] = 'Smoking testing'; +$lang->testcase->stageList['bvt'] = 'BVT testing'; + +$lang->testcase->statusList[''] = ''; +$lang->testcase->statusList['normal'] = 'Normal'; +$lang->testcase->statusList['blocked'] = 'Blocked'; +$lang->testcase->statusList['investigate'] = 'Investigate'; + +$lang->testcase->resultList['n/a'] = 'N/A'; +$lang->testcase->resultList['pass'] = 'Pass'; +$lang->testcase->resultList['fail'] = 'Fail'; +$lang->testcase->resultList['blocked'] = 'Blocked'; + +$lang->testcase->buttonEdit = 'Edit'; +$lang->testcase->buttonToList = 'Back'; diff --git a/module/testcase/lang/zh-cn.php b/module/testcase/lang/zh-cn.php index 5e15dae06f..a29f52e085 100644 --- a/module/testcase/lang/zh-cn.php +++ b/module/testcase/lang/zh-cn.php @@ -1,135 +1,135 @@ - - * @package testcase - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->testcase->id = '用例编号'; -$lang->testcase->product = '所属产品'; -$lang->testcase->module = '所属模块'; -$lang->testcase->story = '相关需求'; -$lang->testcase->storyVersion = '需求版本'; -$lang->testcase->title = '用例标题'; -$lang->testcase->precondition = '前置条件'; -$lang->testcase->pri = '优先级'; -$lang->testcase->type = '用例类型'; -$lang->testcase->status = '用例状态'; -$lang->testcase->steps = '用例步骤'; -$lang->testcase->frequency = '执行频率'; -$lang->testcase->order = '排序'; -$lang->testcase->openedBy = '由谁创建 '; -$lang->testcase->openedDate = '创建日期'; -$lang->testcase->lastEditedBy = '最后修改者'; -$lang->testcase->lastEditedDate = '最后修改日期'; -$lang->testcase->version = '用例版本'; -$lang->testcase->result = '测试结果'; -$lang->testcase->real = '实际情况'; -$lang->testcase->keywords = '关键词'; -$lang->testcase->files = '附件'; -$lang->testcase->howRun = '执行方式'; -$lang->testcase->scriptedBy = '由谁编写'; -$lang->testcase->scriptedDate = '编写日期'; -$lang->testcase->scriptedStatus = '脚本状态'; -$lang->testcase->scriptedLocation = '脚本位置'; -$lang->testcase->linkCase = '相关用例'; -$lang->testcase->stage = '适用阶段'; -$lang->testcase->lastEditedByAB = '修改者'; -$lang->testcase->lastEditedDateAB = '修改日期'; -$lang->testcase->allProduct = '所有产品'; -$lang->case = $lang->testcase; // 用于DAO检查时使用。因为case是系统关键字,所以无法定义该模块为case,只能使用testcase,但表还是使用的case。 - -$lang->testcase->stepID = '编号'; -$lang->testcase->stepDesc = '步骤'; -$lang->testcase->stepExpect = '预期'; - -$lang->testcase->common = '用例管理'; -$lang->testcase->index = "用例管理首页"; -$lang->testcase->create = "创建用例"; -$lang->testcase->batchCreate = "批量添加"; -$lang->testcase->delete = "删除用例"; -$lang->testcase->view = "用例详情"; -$lang->testcase->edit = "编辑用例"; -$lang->testcase->delete = "删除用例"; -$lang->testcase->browse = "用例列表"; -$lang->testcase->export = "导出数据"; -$lang->testcase->confirmStoryChange = '确认需求变动'; - -$lang->testcase->deleteStep = '删除'; -$lang->testcase->insertBefore = '之前添加'; -$lang->testcase->insertAfter = '之后添加'; - -$lang->testcase->selectProduct = '请选择产品'; -$lang->testcase->byModule = '按模块'; -$lang->testcase->assignToMe = '指派给我的用例'; -$lang->testcase->openedByMe = '由我创建的用例'; -$lang->testcase->allCases = '所有Case'; -$lang->testcase->needConfirm = '需求有变动的用例'; -$lang->testcase->moduleCases = '按模块浏览'; -$lang->testcase->bySearch = '搜索'; -$lang->testcase->doneByMe = '我完成的用例'; - -$lang->testcase->lblProductAndModule = '产品模块'; -$lang->testcase->lblTypeAndPri = '类型&优先级'; -$lang->testcase->lblSystemBrowserAndHardware = '系统::浏览器'; -$lang->testcase->lblAssignAndMail = '指派给::抄送给'; -$lang->testcase->lblStory = '相关需求'; -$lang->testcase->lblLastEdited = '最后编辑'; - -$lang->testcase->legendRelated = '相关信息'; -$lang->testcase->legendBasicInfo = '基本信息'; -$lang->testcase->legendMailto = '抄送给'; -$lang->testcase->legendAttatch = '附件'; -$lang->testcase->legendLinkBugs = '相关Bug'; -$lang->testcase->legendOpenAndEdit = '创建编辑'; -$lang->testcase->legendStoryAndTask = '需求::任务'; -$lang->testcase->legendCases = '相关用例'; -$lang->testcase->legendSteps = '用例步骤'; -$lang->testcase->legendAction = '操作'; -$lang->testcase->legendHistory = '历史记录'; -$lang->testcase->legendComment = '备注'; -$lang->testcase->legendProduct = '产品模块'; -$lang->testcase->legendVersion = '版本历史'; - -$lang->testcase->confirmDelete = '您确认要删除该测试用例吗?'; -$lang->testcase->same = '同上'; -$lang->testcase->notes = '(注:“用例类型”和“用例标题”必须填写,否则此行无效)'; - -$lang->testcase->priList[3] = 3; -$lang->testcase->priList[1] = 1; -$lang->testcase->priList[2] = 2; -$lang->testcase->priList[4] = 4; - -/* Define the types. */ -$lang->testcase->typeList[''] = ''; -$lang->testcase->typeList['feature'] = '功能测试'; -$lang->testcase->typeList['performance'] = '性能测试'; -$lang->testcase->typeList['config'] = '配置相关'; -$lang->testcase->typeList['install'] = '安装部署'; -$lang->testcase->typeList['security'] = '安全相关'; -$lang->testcase->typeList['other'] = '其他'; - -$lang->testcase->stageList[''] = ''; -$lang->testcase->stageList['unittest'] = '单元测试阶段'; -$lang->testcase->stageList['feature'] = '功能测试阶段'; -$lang->testcase->stageList['intergrate'] = '集成测试阶段'; -$lang->testcase->stageList['system'] = '系统测试阶段'; -$lang->testcase->stageList['smoke'] = '冒烟测试阶段'; -$lang->testcase->stageList['bvt'] = '版本验证阶段'; - -$lang->testcase->statusList[''] = ''; -$lang->testcase->statusList['normal'] = '正常'; -$lang->testcase->statusList['blocked'] = '被阻塞'; -$lang->testcase->statusList['investigate'] = '研究中'; - -$lang->testcase->resultList['n/a'] = 'N/A'; -$lang->testcase->resultList['pass'] = '通过'; -$lang->testcase->resultList['fail'] = '失败'; -$lang->testcase->resultList['blocked'] = '阻塞'; - -$lang->testcase->buttonEdit = '编辑'; -$lang->testcase->buttonToList = '返回'; + + * @package testcase + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->testcase->id = '用例编号'; +$lang->testcase->product = '所属产品'; +$lang->testcase->module = '所属模块'; +$lang->testcase->story = '相关需求'; +$lang->testcase->storyVersion = '需求版本'; +$lang->testcase->title = '用例标题'; +$lang->testcase->precondition = '前置条件'; +$lang->testcase->pri = '优先级'; +$lang->testcase->type = '用例类型'; +$lang->testcase->status = '用例状态'; +$lang->testcase->steps = '用例步骤'; +$lang->testcase->frequency = '执行频率'; +$lang->testcase->order = '排序'; +$lang->testcase->openedBy = '由谁创建 '; +$lang->testcase->openedDate = '创建日期'; +$lang->testcase->lastEditedBy = '最后修改者'; +$lang->testcase->lastEditedDate = '最后修改日期'; +$lang->testcase->version = '用例版本'; +$lang->testcase->result = '测试结果'; +$lang->testcase->real = '实际情况'; +$lang->testcase->keywords = '关键词'; +$lang->testcase->files = '附件'; +$lang->testcase->howRun = '执行方式'; +$lang->testcase->scriptedBy = '由谁编写'; +$lang->testcase->scriptedDate = '编写日期'; +$lang->testcase->scriptedStatus = '脚本状态'; +$lang->testcase->scriptedLocation = '脚本位置'; +$lang->testcase->linkCase = '相关用例'; +$lang->testcase->stage = '适用阶段'; +$lang->testcase->lastEditedByAB = '修改者'; +$lang->testcase->lastEditedDateAB = '修改日期'; +$lang->testcase->allProduct = '所有产品'; +$lang->case = $lang->testcase; // 用于DAO检查时使用。因为case是系统关键字,所以无法定义该模块为case,只能使用testcase,但表还是使用的case。 + +$lang->testcase->stepID = '编号'; +$lang->testcase->stepDesc = '步骤'; +$lang->testcase->stepExpect = '预期'; + +$lang->testcase->common = '用例管理'; +$lang->testcase->index = "用例管理首页"; +$lang->testcase->create = "创建用例"; +$lang->testcase->batchCreate = "批量添加"; +$lang->testcase->delete = "删除用例"; +$lang->testcase->view = "用例详情"; +$lang->testcase->edit = "编辑用例"; +$lang->testcase->delete = "删除用例"; +$lang->testcase->browse = "用例列表"; +$lang->testcase->export = "导出数据"; +$lang->testcase->confirmStoryChange = '确认需求变动'; + +$lang->testcase->deleteStep = '删除'; +$lang->testcase->insertBefore = '之前添加'; +$lang->testcase->insertAfter = '之后添加'; + +$lang->testcase->selectProduct = '请选择产品'; +$lang->testcase->byModule = '按模块'; +$lang->testcase->assignToMe = '指派给我的用例'; +$lang->testcase->openedByMe = '由我创建的用例'; +$lang->testcase->allCases = '所有Case'; +$lang->testcase->needConfirm = '需求有变动的用例'; +$lang->testcase->moduleCases = '按模块浏览'; +$lang->testcase->bySearch = '搜索'; +$lang->testcase->doneByMe = '我完成的用例'; + +$lang->testcase->lblProductAndModule = '产品模块'; +$lang->testcase->lblTypeAndPri = '类型&优先级'; +$lang->testcase->lblSystemBrowserAndHardware = '系统::浏览器'; +$lang->testcase->lblAssignAndMail = '指派给::抄送给'; +$lang->testcase->lblStory = '相关需求'; +$lang->testcase->lblLastEdited = '最后编辑'; + +$lang->testcase->legendRelated = '相关信息'; +$lang->testcase->legendBasicInfo = '基本信息'; +$lang->testcase->legendMailto = '抄送给'; +$lang->testcase->legendAttatch = '附件'; +$lang->testcase->legendLinkBugs = '相关Bug'; +$lang->testcase->legendOpenAndEdit = '创建编辑'; +$lang->testcase->legendStoryAndTask = '需求::任务'; +$lang->testcase->legendCases = '相关用例'; +$lang->testcase->legendSteps = '用例步骤'; +$lang->testcase->legendAction = '操作'; +$lang->testcase->legendHistory = '历史记录'; +$lang->testcase->legendComment = '备注'; +$lang->testcase->legendProduct = '产品模块'; +$lang->testcase->legendVersion = '版本历史'; + +$lang->testcase->confirmDelete = '您确认要删除该测试用例吗?'; +$lang->testcase->same = '同上'; +$lang->testcase->notes = '(注:“用例类型”和“用例标题”必须填写,否则此行无效)'; + +$lang->testcase->priList[3] = 3; +$lang->testcase->priList[1] = 1; +$lang->testcase->priList[2] = 2; +$lang->testcase->priList[4] = 4; + +/* Define the types. */ +$lang->testcase->typeList[''] = ''; +$lang->testcase->typeList['feature'] = '功能测试'; +$lang->testcase->typeList['performance'] = '性能测试'; +$lang->testcase->typeList['config'] = '配置相关'; +$lang->testcase->typeList['install'] = '安装部署'; +$lang->testcase->typeList['security'] = '安全相关'; +$lang->testcase->typeList['other'] = '其他'; + +$lang->testcase->stageList[''] = ''; +$lang->testcase->stageList['unittest'] = '单元测试阶段'; +$lang->testcase->stageList['feature'] = '功能测试阶段'; +$lang->testcase->stageList['intergrate'] = '集成测试阶段'; +$lang->testcase->stageList['system'] = '系统测试阶段'; +$lang->testcase->stageList['smoke'] = '冒烟测试阶段'; +$lang->testcase->stageList['bvt'] = '版本验证阶段'; + +$lang->testcase->statusList[''] = ''; +$lang->testcase->statusList['normal'] = '正常'; +$lang->testcase->statusList['blocked'] = '被阻塞'; +$lang->testcase->statusList['investigate'] = '研究中'; + +$lang->testcase->resultList['n/a'] = 'N/A'; +$lang->testcase->resultList['pass'] = '通过'; +$lang->testcase->resultList['fail'] = '失败'; +$lang->testcase->resultList['blocked'] = '阻塞'; + +$lang->testcase->buttonEdit = '编辑'; +$lang->testcase->buttonToList = '返回'; diff --git a/module/testcase/lang/zh-tw.php b/module/testcase/lang/zh-tw.php index 85ff55ce6c..d43f6722e7 100644 --- a/module/testcase/lang/zh-tw.php +++ b/module/testcase/lang/zh-tw.php @@ -1,135 +1,135 @@ - - * @package testcase - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->testcase->id = '用例編號'; -$lang->testcase->product = '所屬產品'; -$lang->testcase->module = '所屬模組'; -$lang->testcase->story = '相關需求'; -$lang->testcase->storyVersion = '需求版本'; -$lang->testcase->title = '用例標題'; -$lang->testcase->precondition = '前置條件'; -$lang->testcase->pri = '優先順序'; -$lang->testcase->type = '用例類型'; -$lang->testcase->status = '用例狀態'; -$lang->testcase->steps = '用例步驟'; -$lang->testcase->frequency = '執行頻率'; -$lang->testcase->order = '排序'; -$lang->testcase->openedBy = '由誰創建 '; -$lang->testcase->openedDate = '創建日期'; -$lang->testcase->lastEditedBy = '最後修改者'; -$lang->testcase->lastEditedDate = '最後修改日期'; -$lang->testcase->version = '用例版本'; -$lang->testcase->result = '測試結果'; -$lang->testcase->real = '實際情況'; -$lang->testcase->keywords = '關鍵詞'; -$lang->testcase->files = '附件'; -$lang->testcase->howRun = '執行方式'; -$lang->testcase->scriptedBy = '由誰編寫'; -$lang->testcase->scriptedDate = '編寫日期'; -$lang->testcase->scriptedStatus = '腳本狀態'; -$lang->testcase->scriptedLocation = '腳本位置'; -$lang->testcase->linkCase = '相關用例'; -$lang->testcase->stage = '適用階段'; -$lang->testcase->lastEditedByAB = '修改者'; -$lang->testcase->lastEditedDateAB = '修改日期'; -$lang->testcase->allProduct = '所有產品'; -$lang->case = $lang->testcase; // 用於DAO檢查時使用。因為case是系統關鍵字,所以無法定義該模組為case,只能使用testcase,但表還是使用的case。 - -$lang->testcase->stepID = '編號'; -$lang->testcase->stepDesc = '步驟'; -$lang->testcase->stepExpect = '預期'; - -$lang->testcase->common = '用例管理'; -$lang->testcase->index = "用例管理首頁"; -$lang->testcase->create = "創建用例"; -$lang->testcase->batchCreate = "批量添加"; -$lang->testcase->delete = "刪除用例"; -$lang->testcase->view = "用例詳情"; -$lang->testcase->edit = "編輯用例"; -$lang->testcase->delete = "刪除用例"; -$lang->testcase->browse = "用例列表"; -$lang->testcase->export = "導出數據"; -$lang->testcase->confirmStoryChange = '確認需求變動'; - -$lang->testcase->deleteStep = '刪除'; -$lang->testcase->insertBefore = '之前添加'; -$lang->testcase->insertAfter = '之後添加'; - -$lang->testcase->selectProduct = '請選擇產品'; -$lang->testcase->byModule = '按模組'; -$lang->testcase->assignToMe = '指派給我的用例'; -$lang->testcase->openedByMe = '由我創建的用例'; -$lang->testcase->allCases = '所有Case'; -$lang->testcase->needConfirm = '需求有變動的用例'; -$lang->testcase->moduleCases = '按模組瀏覽'; -$lang->testcase->bySearch = '搜索'; -$lang->testcase->doneByMe = '我完成的用例'; - -$lang->testcase->lblProductAndModule = '產品模組'; -$lang->testcase->lblTypeAndPri = '類型&優先順序'; -$lang->testcase->lblSystemBrowserAndHardware = '系統::瀏覽器'; -$lang->testcase->lblAssignAndMail = '指派給::抄送給'; -$lang->testcase->lblStory = '相關需求'; -$lang->testcase->lblLastEdited = '最後編輯'; - -$lang->testcase->legendRelated = '相關信息'; -$lang->testcase->legendBasicInfo = '基本信息'; -$lang->testcase->legendMailto = '抄送給'; -$lang->testcase->legendAttatch = '附件'; -$lang->testcase->legendLinkBugs = '相關Bug'; -$lang->testcase->legendOpenAndEdit = '創建編輯'; -$lang->testcase->legendStoryAndTask = '需求::任務'; -$lang->testcase->legendCases = '相關用例'; -$lang->testcase->legendSteps = '用例步驟'; -$lang->testcase->legendAction = '操作'; -$lang->testcase->legendHistory = '歷史記錄'; -$lang->testcase->legendComment = '備註'; -$lang->testcase->legendProduct = '產品模組'; -$lang->testcase->legendVersion = '版本歷史'; - -$lang->testcase->confirmDelete = '您確認要刪除該測試用例嗎?'; -$lang->testcase->same = '同上'; -$lang->testcase->notes = '(註:“用例類型”和“用例標題”必須填寫,否則此行無效)'; - -$lang->testcase->priList[3] = 3; -$lang->testcase->priList[1] = 1; -$lang->testcase->priList[2] = 2; -$lang->testcase->priList[4] = 4; - -/* Define the types. */ -$lang->testcase->typeList[''] = ''; -$lang->testcase->typeList['feature'] = '功能測試'; -$lang->testcase->typeList['performance'] = '性能測試'; -$lang->testcase->typeList['config'] = '配置相關'; -$lang->testcase->typeList['install'] = '安裝部署'; -$lang->testcase->typeList['security'] = '安全相關'; -$lang->testcase->typeList['other'] = '其他'; - -$lang->testcase->stageList[''] = ''; -$lang->testcase->stageList['unittest'] = '單元測試階段'; -$lang->testcase->stageList['feature'] = '功能測試階段'; -$lang->testcase->stageList['intergrate'] = '整合測試階段'; -$lang->testcase->stageList['system'] = '系統測試階段'; -$lang->testcase->stageList['smoke'] = '冒煙測試階段'; -$lang->testcase->stageList['bvt'] = '版本驗證階段'; - -$lang->testcase->statusList[''] = ''; -$lang->testcase->statusList['normal'] = '正常'; -$lang->testcase->statusList['blocked'] = '被阻塞'; -$lang->testcase->statusList['investigate'] = '研究中'; - -$lang->testcase->resultList['n/a'] = 'N/A'; -$lang->testcase->resultList['pass'] = '通過'; -$lang->testcase->resultList['fail'] = '失敗'; -$lang->testcase->resultList['blocked'] = '阻塞'; - -$lang->testcase->buttonEdit = '編輯'; -$lang->testcase->buttonToList = '返回'; + + * @package testcase + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->testcase->id = '用例編號'; +$lang->testcase->product = '所屬產品'; +$lang->testcase->module = '所屬模組'; +$lang->testcase->story = '相關需求'; +$lang->testcase->storyVersion = '需求版本'; +$lang->testcase->title = '用例標題'; +$lang->testcase->precondition = '前置條件'; +$lang->testcase->pri = '優先順序'; +$lang->testcase->type = '用例類型'; +$lang->testcase->status = '用例狀態'; +$lang->testcase->steps = '用例步驟'; +$lang->testcase->frequency = '執行頻率'; +$lang->testcase->order = '排序'; +$lang->testcase->openedBy = '由誰創建 '; +$lang->testcase->openedDate = '創建日期'; +$lang->testcase->lastEditedBy = '最後修改者'; +$lang->testcase->lastEditedDate = '最後修改日期'; +$lang->testcase->version = '用例版本'; +$lang->testcase->result = '測試結果'; +$lang->testcase->real = '實際情況'; +$lang->testcase->keywords = '關鍵詞'; +$lang->testcase->files = '附件'; +$lang->testcase->howRun = '執行方式'; +$lang->testcase->scriptedBy = '由誰編寫'; +$lang->testcase->scriptedDate = '編寫日期'; +$lang->testcase->scriptedStatus = '腳本狀態'; +$lang->testcase->scriptedLocation = '腳本位置'; +$lang->testcase->linkCase = '相關用例'; +$lang->testcase->stage = '適用階段'; +$lang->testcase->lastEditedByAB = '修改者'; +$lang->testcase->lastEditedDateAB = '修改日期'; +$lang->testcase->allProduct = '所有產品'; +$lang->case = $lang->testcase; // 用於DAO檢查時使用。因為case是系統關鍵字,所以無法定義該模組為case,只能使用testcase,但表還是使用的case。 + +$lang->testcase->stepID = '編號'; +$lang->testcase->stepDesc = '步驟'; +$lang->testcase->stepExpect = '預期'; + +$lang->testcase->common = '用例管理'; +$lang->testcase->index = "用例管理首頁"; +$lang->testcase->create = "創建用例"; +$lang->testcase->batchCreate = "批量添加"; +$lang->testcase->delete = "刪除用例"; +$lang->testcase->view = "用例詳情"; +$lang->testcase->edit = "編輯用例"; +$lang->testcase->delete = "刪除用例"; +$lang->testcase->browse = "用例列表"; +$lang->testcase->export = "導出數據"; +$lang->testcase->confirmStoryChange = '確認需求變動'; + +$lang->testcase->deleteStep = '刪除'; +$lang->testcase->insertBefore = '之前添加'; +$lang->testcase->insertAfter = '之後添加'; + +$lang->testcase->selectProduct = '請選擇產品'; +$lang->testcase->byModule = '按模組'; +$lang->testcase->assignToMe = '指派給我的用例'; +$lang->testcase->openedByMe = '由我創建的用例'; +$lang->testcase->allCases = '所有Case'; +$lang->testcase->needConfirm = '需求有變動的用例'; +$lang->testcase->moduleCases = '按模組瀏覽'; +$lang->testcase->bySearch = '搜索'; +$lang->testcase->doneByMe = '我完成的用例'; + +$lang->testcase->lblProductAndModule = '產品模組'; +$lang->testcase->lblTypeAndPri = '類型&優先順序'; +$lang->testcase->lblSystemBrowserAndHardware = '系統::瀏覽器'; +$lang->testcase->lblAssignAndMail = '指派給::抄送給'; +$lang->testcase->lblStory = '相關需求'; +$lang->testcase->lblLastEdited = '最後編輯'; + +$lang->testcase->legendRelated = '相關信息'; +$lang->testcase->legendBasicInfo = '基本信息'; +$lang->testcase->legendMailto = '抄送給'; +$lang->testcase->legendAttatch = '附件'; +$lang->testcase->legendLinkBugs = '相關Bug'; +$lang->testcase->legendOpenAndEdit = '創建編輯'; +$lang->testcase->legendStoryAndTask = '需求::任務'; +$lang->testcase->legendCases = '相關用例'; +$lang->testcase->legendSteps = '用例步驟'; +$lang->testcase->legendAction = '操作'; +$lang->testcase->legendHistory = '歷史記錄'; +$lang->testcase->legendComment = '備註'; +$lang->testcase->legendProduct = '產品模組'; +$lang->testcase->legendVersion = '版本歷史'; + +$lang->testcase->confirmDelete = '您確認要刪除該測試用例嗎?'; +$lang->testcase->same = '同上'; +$lang->testcase->notes = '(註:“用例類型”和“用例標題”必須填寫,否則此行無效)'; + +$lang->testcase->priList[3] = 3; +$lang->testcase->priList[1] = 1; +$lang->testcase->priList[2] = 2; +$lang->testcase->priList[4] = 4; + +/* Define the types. */ +$lang->testcase->typeList[''] = ''; +$lang->testcase->typeList['feature'] = '功能測試'; +$lang->testcase->typeList['performance'] = '性能測試'; +$lang->testcase->typeList['config'] = '配置相關'; +$lang->testcase->typeList['install'] = '安裝部署'; +$lang->testcase->typeList['security'] = '安全相關'; +$lang->testcase->typeList['other'] = '其他'; + +$lang->testcase->stageList[''] = ''; +$lang->testcase->stageList['unittest'] = '單元測試階段'; +$lang->testcase->stageList['feature'] = '功能測試階段'; +$lang->testcase->stageList['intergrate'] = '整合測試階段'; +$lang->testcase->stageList['system'] = '系統測試階段'; +$lang->testcase->stageList['smoke'] = '冒煙測試階段'; +$lang->testcase->stageList['bvt'] = '版本驗證階段'; + +$lang->testcase->statusList[''] = ''; +$lang->testcase->statusList['normal'] = '正常'; +$lang->testcase->statusList['blocked'] = '被阻塞'; +$lang->testcase->statusList['investigate'] = '研究中'; + +$lang->testcase->resultList['n/a'] = 'N/A'; +$lang->testcase->resultList['pass'] = '通過'; +$lang->testcase->resultList['fail'] = '失敗'; +$lang->testcase->resultList['blocked'] = '阻塞'; + +$lang->testcase->buttonEdit = '編輯'; +$lang->testcase->buttonToList = '返回'; diff --git a/module/testcase/model.php b/module/testcase/model.php index a45d5c7e7a..93f9cc32e9 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -1,301 +1,301 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -?> -loadModel('product')->setMenu($products, $productID); - $selectHtml = $this->product->select($products, $productID, 'testcase', 'browse'); - foreach($this->lang->testcase->menu as $key => $menu) - { - $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID; - common::setMenuVars($this->lang->testcase->menu, $key, $replace); - } - } - - /** - * Create a case. - * - * @param int $bugID - * @access public - * @return void - */ - function create($bugID) - { - $now = helper::now(); - $case = fixer::input('post') - ->add('openedBy', $this->app->user->account) - ->add('openedDate', $now) - ->add('status', 'normal') - ->add('version', 1) - ->add('fromBug', $bugID) - ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->remove('steps,expects,files,labels') - ->setDefault('story', 0) - ->specialChars('title') - ->join('stage', ',') - ->get(); - $this->dao->insert(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->create->requiredFields, 'notempty')->exec(); - if(!$this->dao->isError()) - { - $caseID = $this->dao->lastInsertID(); - $this->loadModel('file')->saveUpload('testcase', $caseID); - foreach($this->post->steps as $stepID => $stepDesc) - { - if(empty($stepDesc)) continue; - $step->case = $caseID; - $step->version = 1; - $step->desc = htmlspecialchars($stepDesc); - $step->expect = htmlspecialchars($this->post->expects[$stepID]); - $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); - } - return $caseID; - } - } - - /** - * Create a batch case. - * - * @access public - * @return void - */ - function batchCreate($productID) - { - $now = helper::now(); - $cases = fixer::input('post')->get(); - for($i = 0; $i < $this->config->testcase->batchCreate; $i++) - { - if($cases->type[$i] != '' and $cases->title[$i] != '') - { - $data[$i]->product = $productID; - $data[$i]->module = $cases->module[$i] == 'same' ? ($i == 0 ? 0 : $data[$i-1]->module) : $cases->module[$i]; - $data[$i]->type = $cases->type[$i] == 'same' ? ($i == 0 ? '' : $data[$i-1]->type) : $cases->type[$i]; - $data[$i]->story = $cases->story[$i] == 'same' ? ($i == 0 ? 0 : $data[$i-1]->story) : $cases->story[$i]; - $data[$i]->title = $cases->title[$i]; - $data[$i]->openedBy = $this->app->user->account; - $data[$i]->openedDate = $now; - $data[$i]->status = 'normal'; - $data[$i]->version = 1; - if($data[$i]->story != 0) $data[$i]->storyVersion = $this->loadModel('story')->getVersion($this->post->story); - - $this->dao->insert(TABLE_CASE)->data($data[$i]) - ->autoCheck() - ->batchCheck($this->config->testcase->create->requiredFields, 'notempty') - ->exec(); - - if(dao::isError()) - { - echo js::error(dao::getError()); - die(js::reload('parent')); - } - - $caseID = $this->dao->lastInsertID(); - $actionID = $this->loadModel('action')->create('case', $caseID, 'Opened'); - } - else - { - unset($cases->module[$i]); - unset($cases->type[$i]); - unset($cases->story[$i]); - unset($cases->title[$i]); - } - } - } - - /** - * Get cases of a module. - * - * @param int $productID - * @param int $moduleIds - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getModuleCases($productID, $moduleIds = 0, $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('*')->from(TABLE_CASE) - ->where('product')->eq((int)$productID) - ->beginIF($moduleIds)->andWhere('module')->in($moduleIds)->fi() - ->andWhere('deleted')->eq('0') - ->orderBy($orderBy)->page($pager)->fetchAll(); - } - - /** - * Get case info by ID. - * - * @param int $caseID - * @param int $version - * @access public - * @return object|bool - */ - public function getById($caseID, $version = 0) - { - $case = $this->dao->findById($caseID)->from(TABLE_CASE)->fetch(); - if(!$case) return false; - foreach($case as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $case->$key = ''; - if($case->story) - { - $story = $this->dao->findById($case->story)->from(TABLE_STORY)->fields('title, status, version')->fetch(); - $case->storyTitle = $story->title; - $case->storyStatus = $story->status; - $case->latestStoryVersion = $story->version; - } - if($case->linkCase) $case->linkCaseTitles = $this->dao->select('id,title')->from(TABLE_CASE)->where('id')->in($case->linkCase)->fetchPairs(); - if($version == 0) $version = $case->version; - $case->steps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->eq($caseID)->andWhere('version')->eq($version)->fetchAll(); - $case->files = $this->loadModel('file')->getByObject('testcase', $caseID); - $case->currentVersion = $version ? $version : $case->version; - return $case; - } - - /** - * Update a case. - * - * @param int $caseID - * @access public - * @return void - */ - public function update($caseID) - { - $oldCase = $this->getById($caseID); - $now = helper::now(); - $stepChanged = false; - $steps = array(); - - //---------------- Judge steps changed or not.-------------------- */ - - /* Remove the empty setps in post. */ - foreach($this->post->steps as $key => $desc) - { - $desc = trim($desc); - if(!empty($desc)) $steps[] = array('desc' => $desc, 'expect' => trim($this->post->expects[$key])); - } - - /* If step count changed, case changed. */ - if(count($oldCase->steps) != count($steps)) - { - $stepChanged = true; - } - else - { - /* Compare every step. */ - foreach($oldCase->steps as $key => $oldStep) - { - if(trim($oldStep->desc) != trim($steps[$key]['desc']) or trim($oldStep->expect) != $steps[$key]['expect']) - { - $stepChanged = true; - break; - } - } - } - $version = $stepChanged ? $oldCase->version + 1 : $oldCase->version; - - $case = fixer::input('post') - ->add('lastEditedBy', $this->app->user->account) - ->add('lastEditedDate', $now) - ->add('version', $version) - ->setIF($this->post->story != false and $this->post->story != $oldCase->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) - ->setDefault('story', 0) - ->specialChars('title') - ->join('stage', ',') - ->remove('comment,steps,expects,files,labels') - ->get(); - $this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->edit->requiredFields, 'notempty')->where('id')->eq((int)$caseID)->exec(); - if(!$this->dao->isError()) - { - if($stepChanged) - { - foreach($this->post->steps as $stepID => $stepDesc) - { - if(empty($stepDesc)) continue; - $step->case = $caseID; - $step->version = $version; - $step->desc = htmlspecialchars($stepDesc); - $step->expect = htmlspecialchars($this->post->expects[$stepID]); - $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); - } - } - - /* Join the steps to diff. */ - if($stepChanged) - { - $oldCase->steps = $this->joinStep($oldCase->steps); - $case->steps = $this->joinStep($this->getById($caseID, $version)->steps); - } - else - { - unset($oldCase->steps); - } - return common::createChanges($oldCase, $case); - } - } - - /** - * Join steps to a string, thus can diff them. - * - * @param array $steps - * @access public - * @return string - */ - public function joinStep($steps) - { - $retrun = ''; - foreach($steps as $step) $return .= $step->desc . ' EXPECT:' . $step->expect . "\n"; - return $return; - } - - /** - * Create case steps from a bug's step. - * - * @param string $steps - * @access public - * @return array - */ - function createStepsFromBug($steps) - { - $steps = strip_tags($steps); - $caseSteps = array((object)array('desc' => $steps, 'expect' => '')); // the default steps before parse. - $lblStep = strip_tags($this->lang->bug->tplStep); - $lblResult = strip_tags($this->lang->bug->tplResult); - $lblExpect = strip_tags($this->lang->bug->tplExpect); - $lblStepPos = strpos($steps, $lblStep); - $lblResultPos = strpos($steps, $lblResult); - $lblExpectPos = strpos($steps, $lblExpect); - - if($lblStepPos === false or $lblResultPos === false or $lblExpectPos === false) return $caseSteps; - - $caseSteps = substr($steps, $lblStepPos + strlen($lblStep), $lblResultPos - strlen($lblStep)); - $caseExpect = substr($steps, $lblExpectPos + strlen($lblExpect)); - $caseSteps = trim($caseSteps); - $caseExpect = trim($caseExpect); - - $caseSteps = explode("\n", trim($caseSteps)); - $stepCount = count($caseSteps); - foreach($caseSteps as $key => $caseStep) - { - $expect = $key + 1 == $stepCount ? $caseExpect : ''; - $caseSteps[$key] = (object)array('desc' => trim($caseStep), 'expect' => $expect); - } - return $caseSteps; - } -} + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +?> +loadModel('product')->setMenu($products, $productID); + $selectHtml = $this->product->select($products, $productID, 'testcase', 'browse'); + foreach($this->lang->testcase->menu as $key => $menu) + { + $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow : $productID; + common::setMenuVars($this->lang->testcase->menu, $key, $replace); + } + } + + /** + * Create a case. + * + * @param int $bugID + * @access public + * @return void + */ + function create($bugID) + { + $now = helper::now(); + $case = fixer::input('post') + ->add('openedBy', $this->app->user->account) + ->add('openedDate', $now) + ->add('status', 'normal') + ->add('version', 1) + ->add('fromBug', $bugID) + ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->remove('steps,expects,files,labels') + ->setDefault('story', 0) + ->specialChars('title') + ->join('stage', ',') + ->get(); + $this->dao->insert(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->create->requiredFields, 'notempty')->exec(); + if(!$this->dao->isError()) + { + $caseID = $this->dao->lastInsertID(); + $this->loadModel('file')->saveUpload('testcase', $caseID); + foreach($this->post->steps as $stepID => $stepDesc) + { + if(empty($stepDesc)) continue; + $step->case = $caseID; + $step->version = 1; + $step->desc = htmlspecialchars($stepDesc); + $step->expect = htmlspecialchars($this->post->expects[$stepID]); + $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); + } + return $caseID; + } + } + + /** + * Create a batch case. + * + * @access public + * @return void + */ + function batchCreate($productID) + { + $now = helper::now(); + $cases = fixer::input('post')->get(); + for($i = 0; $i < $this->config->testcase->batchCreate; $i++) + { + if($cases->type[$i] != '' and $cases->title[$i] != '') + { + $data[$i]->product = $productID; + $data[$i]->module = $cases->module[$i] == 'same' ? ($i == 0 ? 0 : $data[$i-1]->module) : $cases->module[$i]; + $data[$i]->type = $cases->type[$i] == 'same' ? ($i == 0 ? '' : $data[$i-1]->type) : $cases->type[$i]; + $data[$i]->story = $cases->story[$i] == 'same' ? ($i == 0 ? 0 : $data[$i-1]->story) : $cases->story[$i]; + $data[$i]->title = $cases->title[$i]; + $data[$i]->openedBy = $this->app->user->account; + $data[$i]->openedDate = $now; + $data[$i]->status = 'normal'; + $data[$i]->version = 1; + if($data[$i]->story != 0) $data[$i]->storyVersion = $this->loadModel('story')->getVersion($this->post->story); + + $this->dao->insert(TABLE_CASE)->data($data[$i]) + ->autoCheck() + ->batchCheck($this->config->testcase->create->requiredFields, 'notempty') + ->exec(); + + if(dao::isError()) + { + echo js::error(dao::getError()); + die(js::reload('parent')); + } + + $caseID = $this->dao->lastInsertID(); + $actionID = $this->loadModel('action')->create('case', $caseID, 'Opened'); + } + else + { + unset($cases->module[$i]); + unset($cases->type[$i]); + unset($cases->story[$i]); + unset($cases->title[$i]); + } + } + } + + /** + * Get cases of a module. + * + * @param int $productID + * @param int $moduleIds + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getModuleCases($productID, $moduleIds = 0, $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('*')->from(TABLE_CASE) + ->where('product')->eq((int)$productID) + ->beginIF($moduleIds)->andWhere('module')->in($moduleIds)->fi() + ->andWhere('deleted')->eq('0') + ->orderBy($orderBy)->page($pager)->fetchAll(); + } + + /** + * Get case info by ID. + * + * @param int $caseID + * @param int $version + * @access public + * @return object|bool + */ + public function getById($caseID, $version = 0) + { + $case = $this->dao->findById($caseID)->from(TABLE_CASE)->fetch(); + if(!$case) return false; + foreach($case as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $case->$key = ''; + if($case->story) + { + $story = $this->dao->findById($case->story)->from(TABLE_STORY)->fields('title, status, version')->fetch(); + $case->storyTitle = $story->title; + $case->storyStatus = $story->status; + $case->latestStoryVersion = $story->version; + } + if($case->linkCase) $case->linkCaseTitles = $this->dao->select('id,title')->from(TABLE_CASE)->where('id')->in($case->linkCase)->fetchPairs(); + if($version == 0) $version = $case->version; + $case->steps = $this->dao->select('*')->from(TABLE_CASESTEP)->where('`case`')->eq($caseID)->andWhere('version')->eq($version)->fetchAll(); + $case->files = $this->loadModel('file')->getByObject('testcase', $caseID); + $case->currentVersion = $version ? $version : $case->version; + return $case; + } + + /** + * Update a case. + * + * @param int $caseID + * @access public + * @return void + */ + public function update($caseID) + { + $oldCase = $this->getById($caseID); + $now = helper::now(); + $stepChanged = false; + $steps = array(); + + //---------------- Judge steps changed or not.-------------------- */ + + /* Remove the empty setps in post. */ + foreach($this->post->steps as $key => $desc) + { + $desc = trim($desc); + if(!empty($desc)) $steps[] = array('desc' => $desc, 'expect' => trim($this->post->expects[$key])); + } + + /* If step count changed, case changed. */ + if(count($oldCase->steps) != count($steps)) + { + $stepChanged = true; + } + else + { + /* Compare every step. */ + foreach($oldCase->steps as $key => $oldStep) + { + if(trim($oldStep->desc) != trim($steps[$key]['desc']) or trim($oldStep->expect) != $steps[$key]['expect']) + { + $stepChanged = true; + break; + } + } + } + $version = $stepChanged ? $oldCase->version + 1 : $oldCase->version; + + $case = fixer::input('post') + ->add('lastEditedBy', $this->app->user->account) + ->add('lastEditedDate', $now) + ->add('version', $version) + ->setIF($this->post->story != false and $this->post->story != $oldCase->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->setDefault('story', 0) + ->specialChars('title') + ->join('stage', ',') + ->remove('comment,steps,expects,files,labels') + ->get(); + $this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->edit->requiredFields, 'notempty')->where('id')->eq((int)$caseID)->exec(); + if(!$this->dao->isError()) + { + if($stepChanged) + { + foreach($this->post->steps as $stepID => $stepDesc) + { + if(empty($stepDesc)) continue; + $step->case = $caseID; + $step->version = $version; + $step->desc = htmlspecialchars($stepDesc); + $step->expect = htmlspecialchars($this->post->expects[$stepID]); + $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); + } + } + + /* Join the steps to diff. */ + if($stepChanged) + { + $oldCase->steps = $this->joinStep($oldCase->steps); + $case->steps = $this->joinStep($this->getById($caseID, $version)->steps); + } + else + { + unset($oldCase->steps); + } + return common::createChanges($oldCase, $case); + } + } + + /** + * Join steps to a string, thus can diff them. + * + * @param array $steps + * @access public + * @return string + */ + public function joinStep($steps) + { + $retrun = ''; + foreach($steps as $step) $return .= $step->desc . ' EXPECT:' . $step->expect . "\n"; + return $return; + } + + /** + * Create case steps from a bug's step. + * + * @param string $steps + * @access public + * @return array + */ + function createStepsFromBug($steps) + { + $steps = strip_tags($steps); + $caseSteps = array((object)array('desc' => $steps, 'expect' => '')); // the default steps before parse. + $lblStep = strip_tags($this->lang->bug->tplStep); + $lblResult = strip_tags($this->lang->bug->tplResult); + $lblExpect = strip_tags($this->lang->bug->tplExpect); + $lblStepPos = strpos($steps, $lblStep); + $lblResultPos = strpos($steps, $lblResult); + $lblExpectPos = strpos($steps, $lblExpect); + + if($lblStepPos === false or $lblResultPos === false or $lblExpectPos === false) return $caseSteps; + + $caseSteps = substr($steps, $lblStepPos + strlen($lblStep), $lblResultPos - strlen($lblStep)); + $caseExpect = substr($steps, $lblExpectPos + strlen($lblExpect)); + $caseSteps = trim($caseSteps); + $caseExpect = trim($caseExpect); + + $caseSteps = explode("\n", trim($caseSteps)); + $stepCount = count($caseSteps); + foreach($caseSteps as $key => $caseStep) + { + $expect = $key + 1 == $stepCount ? $caseExpect : ''; + $caseSteps[$key] = (object)array('desc' => trim($caseStep), 'expect' => $expect); + } + return $caseSteps; + } +} diff --git a/module/testcase/view/batchcreate.html.php b/module/testcase/view/batchcreate.html.php index e8fd9ddf31..b524caefe2 100644 --- a/module/testcase/view/batchcreate.html.php +++ b/module/testcase/view/batchcreate.html.php @@ -1,45 +1,45 @@ - - * @package story - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - testcase->batchCreate; $i++):?> - testcase->same; if($i != 0) $currentModuleID = 'same';?> - testcase->typeList['same'] = $lang->testcase->same; $type = ($i == 0 ? 'feature' : 'same');?> - testcase->same; $story = $i == 0 ? '' : 'same';?> - - - - - - - - - - - - -
          testcase->batchCreate;?>
          idAB;?>testcase->module;?>testcase->type;?>testcase->story;?>testcase->title;?>
          testcase->typeList, $type, "class=select-1"); echo "*";?>*";?>
          -
          testcase->notes;?>
          -
          -
          -
          - + + * @package story + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + testcase->batchCreate; $i++):?> + testcase->same; if($i != 0) $currentModuleID = 'same';?> + testcase->typeList['same'] = $lang->testcase->same; $type = ($i == 0 ? 'feature' : 'same');?> + testcase->same; $story = $i == 0 ? '' : 'same';?> + + + + + + + + + + + + +
          testcase->batchCreate;?>
          idAB;?>testcase->module;?>testcase->type;?>testcase->story;?>testcase->title;?>
          testcase->typeList, $type, "class=select-1"); echo "*";?>*";?>
          +
          testcase->notes;?>
          +
          +
          +
          + diff --git a/module/testcase/view/browse.html.php b/module/testcase/view/browse.html.php index 7d4aca1af1..ae278a2459 100644 --- a/module/testcase/view/browse.html.php +++ b/module/testcase/view/browse.html.php @@ -1,106 +1,106 @@ - - * @package testcase - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - -
          -
          - " . $lang->testcase->moduleCases . " "; - echo "" . html::a($this->createLink('testcase', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->testcase->allCases) . ""; - echo "" . html::a($this->createLink('testcase', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->testcase->needConfirm) . ""; - echo "{$lang->testcase->bySearch} "; - ?> -
          -
          - export, '', 'class="export"'); ?> - testcase->batchCreate); ?> - testcase->create); ?> -
          -
          -
          '>
          - - - - - - - -
          -
          -
          - -
          - tree->manage);?> -
          -
          -
          - recTotal}&recPerPage={$pager->recPerPage}"; ?> - - - - - - - - - - - - - - - - - - - - - - id");?> - - - - - - - - - - - - - - - - - - - -
          idAB);?>priAB);?>testcase->title);?>testcase->story);?>actions;?> typeAB);?> openedByAB);?> testtask->lastRunAccount);?> testtask->lastRunTime);?> testtask->lastRunResult);?>statusAB);?>actions;?>
          id));?>pri?>title);?>createLink('story', 'view', "storyID=$case->story"), $case->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin');?>testcase->typeList[$case->type];?>openedBy];?>lastRunner];?>lastRunDate)) echo date(DT_MONTHTIME1, strtotime($case->lastRunDate));?>lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?>testcase->statusList[$case->status];?> - product&moduleID=$case->module&from=testcase¶m=$case->id", $lang->copy); - common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); - common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); - common::printLink('testtask', 'runCase', "runID=0&caseID=$case->id&version=$case->version", $this->app->loadLang('testtask')->testtask->runCase, '', 'class="runcase"'); - common::printLink('testtask', 'results', "runID=0&caseID=$case->id", $lang->testtask->results, '', 'class="results"'); - if(!($case->lastRunResult == 'fail' and common::printLink('bug', 'create', "product=$case->product&extra=caseID=$case->id,version=$case->version,runID=", $lang->testtask->createBug))) echo $lang->testtask->createBug; - ?> -
          show();?>
          -
          - + + * @package testcase + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + +
          +
          + " . $lang->testcase->moduleCases . " "; + echo "" . html::a($this->createLink('testcase', 'browse', "productid=$productID&browseType=all¶m=0&orderBy=$orderBy&recTotal=0&recPerPage=200"), $lang->testcase->allCases) . ""; + echo "" . html::a($this->createLink('testcase', 'browse', "productid=$productID&browseType=needconfirm¶m=0"), $lang->testcase->needConfirm) . ""; + echo "{$lang->testcase->bySearch} "; + ?> +
          +
          + export, '', 'class="export"'); ?> + testcase->batchCreate); ?> + testcase->create); ?> +
          +
          +
          '>
          + + + + + + + +
          +
          +
          + +
          + tree->manage);?> +
          +
          +
          + recTotal}&recPerPage={$pager->recPerPage}"; ?> + + + + + + + + + + + + + + + + + + + + + + id");?> + + + + + + + + + + + + + + + + + + + +
          idAB);?>priAB);?>testcase->title);?>testcase->story);?>actions;?> typeAB);?> openedByAB);?> testtask->lastRunAccount);?> testtask->lastRunTime);?> testtask->lastRunResult);?>statusAB);?>actions;?>
          id));?>pri?>title);?>createLink('story', 'view', "storyID=$case->story"), $case->storyTitle, '_blank');?>id"), $lang->confirm, 'hiddenwin');?>testcase->typeList[$case->type];?>openedBy];?>lastRunner];?>lastRunDate)) echo date(DT_MONTHTIME1, strtotime($case->lastRunDate));?>lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?>testcase->statusList[$case->status];?> + product&moduleID=$case->module&from=testcase¶m=$case->id", $lang->copy); + common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); + common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); + common::printLink('testtask', 'runCase', "runID=0&caseID=$case->id&version=$case->version", $this->app->loadLang('testtask')->testtask->runCase, '', 'class="runcase"'); + common::printLink('testtask', 'results', "runID=0&caseID=$case->id", $lang->testtask->results, '', 'class="results"'); + if(!($case->lastRunResult == 'fail' and common::printLink('bug', 'create', "product=$case->product&extra=caseID=$case->id,version=$case->version,runID=", $lang->testtask->createBug))) echo $lang->testtask->createBug; + ?> +
          show();?>
          +
          + diff --git a/module/testcase/view/create.html.php b/module/testcase/view/create.html.php index 5db36d6a2b..06c6562fa4 100644 --- a/module/testcase/view/create.html.php +++ b/module/testcase/view/create.html.php @@ -1,97 +1,97 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testcase->create;?>
          testcase->lblProductAndModule;?> - - -
          testcase->type;?>testcase->typeList, $type, 'class=select-3');?>
          testcase->stage;?>testcase->stageList, $stage, "class='select-3' multiple='multiple'");?>
          testcase->pri;?>testcase->priList, $pri, 'class=select-3');?>
          testcase->lblStory;?> - - - - - createLink('story', 'view', "storyID=$storyID"), $lang->preview, '', "class='iframe' id='preview'");?> - -
          testcase->title;?>
          testcase->precondition;?>
          testcase->steps;?> - - - - - - - - $step) - { - $stepID += 1; - echo ""; - echo ""; - echo ''; - echo ''; - echo ""; - echo ''; - } - ?> -
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>actions;?>
          $stepID' . html::textarea('steps[]', $step->desc, "rows='3' class='w-p100'") . '' . html::textarea('expects[]', $step->expect, "rows='3' class='w-p100'") . '"; - echo "
          "; - echo "
          "; - echo "
          "; - echo "
          -
          testcase->keywords;?>
          testcase->files;?>fetch('file', 'buildform');?>
          -
          - + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testcase->create;?>
          testcase->lblProductAndModule;?> + + +
          testcase->type;?>testcase->typeList, $type, 'class=select-3');?>
          testcase->stage;?>testcase->stageList, $stage, "class='select-3' multiple='multiple'");?>
          testcase->pri;?>testcase->priList, $pri, 'class=select-3');?>
          testcase->lblStory;?> + + + + + createLink('story', 'view', "storyID=$storyID"), $lang->preview, '', "class='iframe' id='preview'");?> + +
          testcase->title;?>
          testcase->precondition;?>
          testcase->steps;?> + + + + + + + + $step) + { + $stepID += 1; + echo ""; + echo ""; + echo ''; + echo ''; + echo ""; + echo ''; + } + ?> +
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>actions;?>
          $stepID' . html::textarea('steps[]', $step->desc, "rows='3' class='w-p100'") . '' . html::textarea('expects[]', $step->expect, "rows='3' class='w-p100'") . '"; + echo "
          "; + echo "
          "; + echo "
          "; + echo "
          +
          testcase->keywords;?>
          testcase->files;?>fetch('file', 'buildform');?>
          +
          + diff --git a/module/testcase/view/edit.html.php b/module/testcase/view/edit.html.php index 4ee8fb894f..67395aad60 100644 --- a/module/testcase/view/edit.html.php +++ b/module/testcase/view/edit.html.php @@ -1,132 +1,132 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          -
          - CASE #id . $lang->colon;?> - title, 'class=text-1');?> -
          -
          -
          - - - - - - - -
          - -
          - testcase->precondition;?> - precondition, "rows='4' class='w-p100'");?> -
          - - - - - - - steps as $stepID => $step) - { - $stepID += 1; - echo ""; - echo ""; - echo ''; - echo ''; - echo ""; - echo ''; - } - ?> -
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>actions;?>
          $stepID' . html::textarea('steps[]', $step->desc, "rows='3' class='w-p100'") . '' . html::textarea('expects[]', $step->expect, "rows='3' class='w-p100'") . '"; - echo "
          "; - echo "
          "; - echo "
          "; - echo "
          - -
          - testcase->legendComment;?> - -
          -
          - testcase->legendAttatch;?> - fetch('file', 'buildform', 'filecount=2');?> -
          - -
          - - "' /> -
          - - -
          -
          - testcase->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testcase->product;?>
          testcase->module;?>
          testcase->story;?>
          story, 'class=select-1');?>
          - -
          testcase->type;?>testcase->typeList, $case->type, 'class=select-1');?> -
          testcase->stage;?>testcase->stageList, $case->stage, "class='select-1' multiple='multiple'");?>
          testcase->pri;?>testcase->priList, $case->pri, 'class=select-1');?> -
          testcase->status;?>testcase->statusList, $case->status, 'class=select-1');?>
          testcase->keywords;?>keywords, 'class=text-1');?>
          testcase->linkCase;?>linkCase, 'class=text-1');?>
          -
          -
          - testcase->legendOpenAndEdit;?> - - - - - - - - -
          testcase->openedBy;?>openedBy . $lang->at . $case->openedDate;?>
          testcase->lblLastEdited;?>lastEditedBy) echo $case->lastEditedBy . $lang->at . $case->lastEditedDate;?>
          -
          -
          - + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          +
          + CASE #id . $lang->colon;?> + title, 'class=text-1');?> +
          +
          +
          + + + + + + + +
          + +
          + testcase->precondition;?> + precondition, "rows='4' class='w-p100'");?> +
          + + + + + + + steps as $stepID => $step) + { + $stepID += 1; + echo ""; + echo ""; + echo ''; + echo ''; + echo ""; + echo ''; + } + ?> +
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>actions;?>
          $stepID' . html::textarea('steps[]', $step->desc, "rows='3' class='w-p100'") . '' . html::textarea('expects[]', $step->expect, "rows='3' class='w-p100'") . '"; + echo "
          "; + echo "
          "; + echo "
          "; + echo "
          + +
          + testcase->legendComment;?> + +
          +
          + testcase->legendAttatch;?> + fetch('file', 'buildform', 'filecount=2');?> +
          + +
          + + "' /> +
          + + +
          +
          + testcase->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testcase->product;?>
          testcase->module;?>
          testcase->story;?>
          story, 'class=select-1');?>
          + +
          testcase->type;?>testcase->typeList, $case->type, 'class=select-1');?> +
          testcase->stage;?>testcase->stageList, $case->stage, "class='select-1' multiple='multiple'");?>
          testcase->pri;?>testcase->priList, $case->pri, 'class=select-1');?> +
          testcase->status;?>testcase->statusList, $case->status, 'class=select-1');?>
          testcase->keywords;?>keywords, 'class=text-1');?>
          testcase->linkCase;?>linkCase, 'class=text-1');?>
          +
          +
          + testcase->legendOpenAndEdit;?> + + + + + + + + +
          testcase->openedBy;?>openedBy . $lang->at . $case->openedDate;?>
          testcase->lblLastEdited;?>lastEditedBy) echo $case->lastEditedBy . $lang->at . $case->lastEditedDate;?>
          +
          +
          + diff --git a/module/testcase/view/export.html.php b/module/testcase/view/export.html.php index d6d1f976d9..a80d0f7dc8 100755 --- a/module/testcase/view/export.html.php +++ b/module/testcase/view/export.html.php @@ -1,13 +1,13 @@ - - * @package testcase - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + + * @package testcase + * @version $Id$ + * @link http://www.zentao.net + */ +?> + diff --git a/module/testcase/view/index.html.php b/module/testcase/view/index.html.php index 53c3b719b1..61e8305262 100644 --- a/module/testcase/view/index.html.php +++ b/module/testcase/view/index.html.php @@ -1,16 +1,16 @@ - - * @package bug - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          -
          + + * @package bug + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          +
          \ No newline at end of file diff --git a/module/testcase/view/view.html.php b/module/testcase/view/view.html.php index aa8c6f1d71..9cf4134600 100644 --- a/module/testcase/view/view.html.php +++ b/module/testcase/view/view.html.php @@ -1,198 +1,198 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          deleted) echo "class='deleted'";?>> - CASE #id . $lang->colon . $case->title;?> -
          - session->caseList != false ? $app->session->caseList : $this->createLink('testcase', 'browse', "productID=$case->product"); - if(!$case->deleted) - { - common::printLink('testtask', 'runCase', "runID=0&caseID=$case->id&version=$case->currentVersion", $this->app->loadLang('testtask')->testtask->runCase, '', 'class="runcase"'); - common::printLink('testtask', 'results', "runID=0&caseID=$case->id&version=$case->version", $lang->testtask->results, '', 'class="results"'); - if($case->lastRunResult == 'fail') common::printLink('bug', 'create', "product=$case->product&extra=caseID=$case->id,version=$case->version,runID=", $lang->testtask->createBug); - if(common::hasPriv('testcase', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); - common::printLink('testcase', 'create', "productID=$case->product&moduleID=$case->module&from=testcase¶m=$case->id", $lang->copy); - common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          -
          - - - - - - - -
          - -
          - testcase->precondition;?> - precondition;?> -
          - - - - - - steps as $stepID => $step) - { - $stepID += 1; - echo ""; - echo ""; - echo ""; - echo ""; - } - ?> -
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>
          $stepID" . nl2br($step->desc) . "" . nl2br($step->expect) . "
          - fetch('file', 'printFiles', array('files' => $case->files, 'fieldset' => 'true'));?> - -
          - deleted) - { - if(common::hasPriv('testcase', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; - common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); - common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - -
          -
          - testcase->legendBasicInfo;?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testcase->product;?>product", $productName)) echo $productName;?>
          testcase->module;?> - $module) - { - if(!common::printLink('testcase', 'browse', "productID=$case->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; - if(isset($modulePath[$key + 1])) echo $lang->arrow; - } - ?> -
          testcase->story;?> - storyTitle)) echo html::a($this->createLink('story', 'view', "storyID=$case->story"), "#$case->story:$case->storyTitle"); - if($case->story and $case->storyStatus == 'active' and $case->latestStoryVersion > $case->storyVersion) - { - echo "({$lang->story->changed} "; - echo html::a($this->createLink('testcase', 'confirmStoryChange', "caseID=$case->id"), $lang->confirm, 'hiddenwin'); - echo ")"; - } - ?> -
          testcase->type;?>testcase->typeList[$case->type];?>
          testcase->stage;?> - stage) - { - $stags = explode(',', $case->stage); - foreach($stags as $stage) - { - isset($lang->testcase->stageList[$stage]) ? print($lang->testcase->stageList[$stage]) : print($stage); - echo "
          "; - } - } - ?> -
          testcase->pri;?>pri;?>
          testcase->status;?>testcase->statusList[$case->status];?>
          app->loadLang('testtask')->testtask->lastRunTime;?>lastRunDate)) echo $case->lastRunDate;?>
          app->loadLang('testtask')->testtask->lastRunResult;?>lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?>
          testcase->keywords;?>keywords;?>
          testcase->linkCase;?> - linkCaseTitles)) - { - foreach($case->linkCaseTitles as $linkCaseID => $linkCaseTitle) - { - echo html::a($this->createLink('testcase', 'view', "caseID=$linkCaseID"), "#$linkCaseID $linkCaseTitle", '_blank') . '
          '; - } - } - ?> -
          -
          - -
          - testcase->legendOpenAndEdit;?> - - - - - - - - - -
          testcase->openedBy;?>openedBy . $lang->at . $case->openedDate;?>
          testcase->lblLastEdited;?>lastEditedBy) echo $case->lastEditedBy . $lang->at . $case->lastEditedDate;?>
          -
          -
          - testcase->legendVersion;?> -
          - version; $i >= 1; $i --) echo html::a(inlink('view', "caseID=$case->id&version=$i"), '#' . $i) . ' ';?> -
          -
          -
          - + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          deleted) echo "class='deleted'";?>> + CASE #id . $lang->colon . $case->title;?> +
          + session->caseList != false ? $app->session->caseList : $this->createLink('testcase', 'browse', "productID=$case->product"); + if(!$case->deleted) + { + common::printLink('testtask', 'runCase', "runID=0&caseID=$case->id&version=$case->currentVersion", $this->app->loadLang('testtask')->testtask->runCase, '', 'class="runcase"'); + common::printLink('testtask', 'results', "runID=0&caseID=$case->id&version=$case->version", $lang->testtask->results, '', 'class="results"'); + if($case->lastRunResult == 'fail') common::printLink('bug', 'create', "product=$case->product&extra=caseID=$case->id,version=$case->version,runID=", $lang->testtask->createBug); + if(common::hasPriv('testcase', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); + common::printLink('testcase', 'create', "productID=$case->product&moduleID=$case->module&from=testcase¶m=$case->id", $lang->copy); + common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          +
          + + + + + + + +
          + +
          + testcase->precondition;?> + precondition;?> +
          + + + + + + steps as $stepID => $step) + { + $stepID += 1; + echo ""; + echo ""; + echo ""; + echo ""; + } + ?> +
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>
          $stepID" . nl2br($step->desc) . "" . nl2br($step->expect) . "
          + fetch('file', 'printFiles', array('files' => $case->files, 'fieldset' => 'true'));?> + +
          + deleted) + { + if(common::hasPriv('testcase', 'edit')) echo html::a('#', $lang->comment, '', 'onclick=setComment()'). ' '; + common::printLink('testcase', 'edit', "caseID=$case->id", $lang->testcase->buttonEdit); + common::printLink('testcase', 'delete', "caseID=$case->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + +
          +
          + testcase->legendBasicInfo;?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testcase->product;?>product", $productName)) echo $productName;?>
          testcase->module;?> + $module) + { + if(!common::printLink('testcase', 'browse', "productID=$case->product&browseType=byModule¶m=$module->id", $module->name)) echo $module->name; + if(isset($modulePath[$key + 1])) echo $lang->arrow; + } + ?> +
          testcase->story;?> + storyTitle)) echo html::a($this->createLink('story', 'view', "storyID=$case->story"), "#$case->story:$case->storyTitle"); + if($case->story and $case->storyStatus == 'active' and $case->latestStoryVersion > $case->storyVersion) + { + echo "({$lang->story->changed} "; + echo html::a($this->createLink('testcase', 'confirmStoryChange', "caseID=$case->id"), $lang->confirm, 'hiddenwin'); + echo ")"; + } + ?> +
          testcase->type;?>testcase->typeList[$case->type];?>
          testcase->stage;?> + stage) + { + $stags = explode(',', $case->stage); + foreach($stags as $stage) + { + isset($lang->testcase->stageList[$stage]) ? print($lang->testcase->stageList[$stage]) : print($stage); + echo "
          "; + } + } + ?> +
          testcase->pri;?>pri;?>
          testcase->status;?>testcase->statusList[$case->status];?>
          app->loadLang('testtask')->testtask->lastRunTime;?>lastRunDate)) echo $case->lastRunDate;?>
          app->loadLang('testtask')->testtask->lastRunResult;?>lastRunResult) echo $lang->testcase->resultList[$case->lastRunResult];?>
          testcase->keywords;?>keywords;?>
          testcase->linkCase;?> + linkCaseTitles)) + { + foreach($case->linkCaseTitles as $linkCaseID => $linkCaseTitle) + { + echo html::a($this->createLink('testcase', 'view', "caseID=$linkCaseID"), "#$linkCaseID $linkCaseTitle", '_blank') . '
          '; + } + } + ?> +
          +
          + +
          + testcase->legendOpenAndEdit;?> + + + + + + + + + +
          testcase->openedBy;?>openedBy . $lang->at . $case->openedDate;?>
          testcase->lblLastEdited;?>lastEditedBy) echo $case->lastEditedBy . $lang->at . $case->lastEditedDate;?>
          +
          +
          + testcase->legendVersion;?> +
          + version; $i >= 1; $i --) echo html::a(inlink('view', "caseID=$case->id&version=$i"), '#' . $i) . ' ';?> +
          +
          +
          + diff --git a/module/testtask/control.php b/module/testtask/control.php index 9bd0cdac00..2642f0229e 100644 --- a/module/testtask/control.php +++ b/module/testtask/control.php @@ -1,471 +1,471 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -class testtask extends control -{ - private $products = array(); - - /** - * Construct function, load product module, assign products to view auto. - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('product'); - $this->view->products = $this->products = $this->product->getPairs(); - } - - /** - * Index page, header to browse. - * - * @access public - * @return void - */ - public function index() - { - $this->locate($this->createLink('testtask', 'browse')); - } - - /** - * Browse test tasks. - * - * @param int $productID - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function browse($productID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* Save session. */ - $this->session->set('testtaskList', $this->app->getURI(true)); - - /* Set menu. */ - $productID = $this->product->saveState($productID, $this->products); - $this->testtask->setMenu($this->products, $productID); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->common; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->common; - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->pager = $pager; - $this->view->orderBy = $orderBy; - $this->view->tasks = $this->testtask->getProductTasks($productID); - $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); - - $this->display(); - } - - /** - * Create a test task. - * - * @param int $productID - * @access public - * @return void - */ - public function create($productID, $projectID = 0, $build = 0) - { - if(!empty($_POST)) - { - $taskID = $this->testtask->create(); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('testtask', $taskID, 'opened'); - die(js::locate($this->createLink('testtask', 'browse', "productID=$productID"), 'parent')); - } - - /* Create testtask from build of project.*/ - if($projectID != 0 and $build != 0) - { - $products = $this->dao->select('t2.id, t2.name') - ->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product = t2.id') - ->where('t1.project')->eq($projectID) - ->fetchPairs('id'); - - foreach($products as $key => $value) - { - $productID = $key; - break; - } - - $projects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetchPairs('id'); - $builds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->eq($build)->fetchPairs('id'); - } - - /* Create testtask from testtask of project.*/ - if($projectID != 0 and $build == 0) - { - $products = $this->dao->select('t2.id, t2.name') - ->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2') - ->on('t1.product = t2.id') - ->where('t1.project')->eq($projectID) - ->fetchPairs('id'); - - foreach($products as $key => $value) - { - $productID = $key; - break; - } - - $projects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetchPairs('id'); - $builds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('project')->eq($projectID)->fetchPairs('id'); - } - - /* Create testtask from testtask of test.*/ - if($projectID == 0) - { - $projects = $this->product->getProjectPairs($productID, $params = 'nodeleted'); - $builds = $this->loadModel('build')->getProductBuildPairs($productID); - } - - /* Set menu. */ - $productID = $this->product->saveState($productID, $this->products); - $this->testtask->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->create; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->create; - - if($projectID != 0) - { - $this->view->products = $products; - $this->view->projectID = $projectID; - } - $this->view->projects = $projects; - $this->view->productID = $productID; - $this->view->builds = $builds; - $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); - - $this->display(); - } - - /** - * View a test task. - * - * @param int $taskID - * @access public - * @return void - */ - public function view($taskID) - { - /* Get test task, and set menu. */ - $task = $this->testtask->getById($taskID); - if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); - $productID = $task->product; - $this->testtask->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->view; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->view; - - $this->view->productID = $productID; - $this->view->task = $task; - $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); - $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID); - - $this->display(); - } - - /** - * Browse cases of a test task. - * - * @param int $taskID - * @param string $browseType bymodule|all|assignedtome - * @param int $param - * @access public - * @return void - */ - public function cases($taskID, $browseType = 'byModule', $param = 0) - { - /* Save the session. */ - $this->app->loadLang('testcase'); - $this->session->set('caseList', $this->app->getURI(true)); - - /* Set the browseType and moduleID. */ - $browseType = strtolower($browseType); - $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; - - /* Get task and product info, set menu. */ - $task = $this->testtask->getById($taskID); - if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); - $productID = $task->product; - $this->testtask->setMenu($this->products, $productID); - - if($browseType == 'bymodule' or $browseType == 'all') - { - $modules = ''; - if($moduleID) $modules = $this->loadModel('tree')->getAllChildID($moduleID); - $this->view->runs = $this->testtask->getRuns($taskID, $modules); - } - elseif($browseType == 'assignedtome') - { - $this->view->runs = $this->testtask->getUserRuns($taskID, $this->session->user->account); - } - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->cases; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->cases; - - $this->view->productID = $productID; - $this->view->productName = $this->products[$productID]; - $this->view->task = $task; - $this->view->users = $this->loadModel('user')->getPairs('noclosed'); - $this->view->moduleTree = $this->loadModel('tree')->getTreeMenu($productID, $viewType = 'case', $startModuleID = 0, array('treeModel', 'createTestTaskLink'), $extra = $taskID); - $this->view->browseType = $browseType; - $this->view->taskID = $taskID; - $this->view->moduleID = $moduleID; - $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; - - $this->display(); - } - - /** - * Edit a test task. - * - * @param int $taskID - * @access public - * @return void - */ - public function edit($taskID) - { - if(!empty($_POST)) - { - $changes = $this->testtask->update($taskID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('testtask', $taskID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "taskID=$taskID"), 'parent')); - } - - /* Get task info. */ - $task = $this->testtask->getById($taskID); - $productID = $this->product->saveState($task->product, $this->products); - - /* Set menu. */ - $this->testtask->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->edit; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->edit; - - $this->view->task = $task; - $this->view->projects = $this->product->getProjectPairs($productID); - $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); - $this->view->users = $this->loadModel('user')->getPairs(); - - $this->display(); - } - - /** - * Delete a test task. - * - * @param int $taskID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($taskID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->testtask->confirmDelete, inlink('delete', "taskID=$taskID&confirm=yes"))); - } - else - { - $task = $this->testtask->getByID($taskID); - $this->testtask->delete(TABLE_TESTTASK, $taskID); - die(js::locate(inlink('browse', "product=$task->product"), 'parent')); - } - } - - /** - * Link cases to a test task. - * - * @param int $taskID - * @access public - * @return void - */ - public function linkCase($taskID, $param = 'all', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - if(!empty($_POST)) - { - $this->testtask->linkCase($taskID); - $this->locate(inlink('cases', "taskID=$taskID")); - } - - /* Save session. */ - $this->session->set('caseList', $this->app->getURI(true)); - - /* Get task and product id. */ - $task = $this->testtask->getById($taskID); - $productID = $this->product->saveState($task->product, $this->products); - - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - - /* Build the search form. */ - $this->loadModel('testcase'); - $this->config->testcase->search['params']['product']['values']= array($productID => $this->products[$productID], 'all' => $this->lang->testcase->allProduct); - $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case'); - $this->config->testcase->search['actionURL'] = inlink('linkcase', "taskID=$taskID"); - $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->testcase->search); - - /* Save session. */ - $this->testtask->setMenu($this->products, $productID); - - $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->linkCase; - $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); - $this->view->position[] = $this->lang->testtask->linkCase; - - /* Get cases. */ - if($this->session->testcaseQuery == false) $this->session->set('testcaseQuery', ' 1 = 1'); - $query = str_replace("`product` = 'all'", '1', $this->session->testcaseQuery); // If search all product, replace product = all to 1=1 - $linkedCases = $this->dao->select('`case`')->from(TABLE_TESTRUN)->where('task')->eq($taskID)->fetchPairs('case'); - if($param == 'all') - { - $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) - ->andWhere('product')->eq($productID) - ->andWhere('id')->notIN($linkedCases) - ->andWhere('deleted')->eq(0) - ->orderBy('id desc') - ->page($pager) - ->fetchAll(); - } - if($param == 'bystory') - { - $stories = $this->dao->select('stories')->from(TABLE_BUILD)->where('id')->eq($task->build)->fetch('stories'); - - $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) - ->andWhere('product')->eq($productID) - ->beginIF($linkedCases)->andWhere('id')->notIN($linkedCases)->fi() - ->andWhere('story')->in($stories) - ->andWhere('deleted')->eq(0) - ->orderBy('id desc') - ->page($pager) - ->fetchAll(); - } - if($param == 'bybug') - { - $bugs = $this->dao->select('bugs')->from(TABLE_BUILD)->where('id')->eq($task->build)->fetch('bugs'); - $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) - ->andWhere('product')->eq($productID) - ->beginIF($linkedCases)->andWhere('id')->notIN($linkedCases)->fi() - ->andWhere('fromBug')->in($bugs) - ->andWhere('deleted')->eq(0) - ->orderBy('id desc') - ->page($pager) - ->fetchAll(); - } - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->cases = $cases; - $this->view->taskID = $taskID; - $this->view->pager = $pager; - - $this->display(); - } - - /** - * Remove a case from test task. - * - * @param int $rowID - * @access public - * @return void - */ - public function unlinkCase($rowID) - { - $this->dao->delete()->from(TABLE_TESTRUN)->where('id')->eq((int)$rowID)->exec(); - die(js::reload('parent')); - } - - /** - * Run case. - * - * @param int $runID - * @param String $extras others params, forexample, caseID=10, version=3 - * @access public - * @return void - */ - public function runCase($runID, $caseID = 0, $version = 0) - { - if(!empty($_POST)) - { - $this->testtask->createResult($runID); - if(dao::isError()) die(js::error(dao::getError())); - echo js::reload('parent'); - die(js::closeWindow()); - } - - if(!$caseID) $run = $this->testtask->getRunById($runID); - if($caseID) $run->case = $this->loadModel('testcase')->getById($caseID, $version); - - $this->view->run = $run; - - die($this->display()); - } - - /** - * View test results of a test run. - * - * @param int $runID - * @param int $caseID - * @access public - * @return void - */ - public function results($runID, $caseID = 0, $version = 0) - { - if($caseID) - { - $this->view->case = $this->loadModel('testcase')->getByID($caseID, $version); - $this->view->results = $this->testtask->getResults(0, $caseID); - } - else - { - $this->view->case = $this->testtask->getRunById($runID)->case; - $this->view->results = $this->testtask->getResults($runID); - } - $this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter'); - - die($this->display()); - } - - /** - * Batch assign cases. - * - * @param int $taskID - * @access public - * @return void - */ - public function batchAssign($taskID) - { - $this->dao->update(TABLE_TESTRUN) - ->set('assignedTo')->eq($this->post->assignedTo) - ->where('task')->eq((int)$taskID) - ->andWhere('`case`')->in($this->post->cases) - ->exec(); - die(js::reload('parent')); - } -} + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +class testtask extends control +{ + private $products = array(); + + /** + * Construct function, load product module, assign products to view auto. + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('product'); + $this->view->products = $this->products = $this->product->getPairs(); + } + + /** + * Index page, header to browse. + * + * @access public + * @return void + */ + public function index() + { + $this->locate($this->createLink('testtask', 'browse')); + } + + /** + * Browse test tasks. + * + * @param int $productID + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($productID = 0, $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* Save session. */ + $this->session->set('testtaskList', $this->app->getURI(true)); + + /* Set menu. */ + $productID = $this->product->saveState($productID, $this->products); + $this->testtask->setMenu($this->products, $productID); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $this->view->header->title = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->common; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->common; + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->pager = $pager; + $this->view->orderBy = $orderBy; + $this->view->tasks = $this->testtask->getProductTasks($productID); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); + + $this->display(); + } + + /** + * Create a test task. + * + * @param int $productID + * @access public + * @return void + */ + public function create($productID, $projectID = 0, $build = 0) + { + if(!empty($_POST)) + { + $taskID = $this->testtask->create(); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('testtask', $taskID, 'opened'); + die(js::locate($this->createLink('testtask', 'browse', "productID=$productID"), 'parent')); + } + + /* Create testtask from build of project.*/ + if($projectID != 0 and $build != 0) + { + $products = $this->dao->select('t2.id, t2.name') + ->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product = t2.id') + ->where('t1.project')->eq($projectID) + ->fetchPairs('id'); + + foreach($products as $key => $value) + { + $productID = $key; + break; + } + + $projects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetchPairs('id'); + $builds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('id')->eq($build)->fetchPairs('id'); + } + + /* Create testtask from testtask of project.*/ + if($projectID != 0 and $build == 0) + { + $products = $this->dao->select('t2.id, t2.name') + ->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2') + ->on('t1.product = t2.id') + ->where('t1.project')->eq($projectID) + ->fetchPairs('id'); + + foreach($products as $key => $value) + { + $productID = $key; + break; + } + + $projects = $this->dao->select('id, name')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetchPairs('id'); + $builds = $this->dao->select('id, name')->from(TABLE_BUILD)->where('project')->eq($projectID)->fetchPairs('id'); + } + + /* Create testtask from testtask of test.*/ + if($projectID == 0) + { + $projects = $this->product->getProjectPairs($productID, $params = 'nodeleted'); + $builds = $this->loadModel('build')->getProductBuildPairs($productID); + } + + /* Set menu. */ + $productID = $this->product->saveState($productID, $this->products); + $this->testtask->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->create; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->create; + + if($projectID != 0) + { + $this->view->products = $products; + $this->view->projectID = $projectID; + } + $this->view->projects = $projects; + $this->view->productID = $productID; + $this->view->builds = $builds; + $this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted'); + + $this->display(); + } + + /** + * View a test task. + * + * @param int $taskID + * @access public + * @return void + */ + public function view($taskID) + { + /* Get test task, and set menu. */ + $task = $this->testtask->getById($taskID); + if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); + $productID = $task->product; + $this->testtask->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->view; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->view; + + $this->view->productID = $productID; + $this->view->task = $task; + $this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter'); + $this->view->actions = $this->loadModel('action')->getList('testtask', $taskID); + + $this->display(); + } + + /** + * Browse cases of a test task. + * + * @param int $taskID + * @param string $browseType bymodule|all|assignedtome + * @param int $param + * @access public + * @return void + */ + public function cases($taskID, $browseType = 'byModule', $param = 0) + { + /* Save the session. */ + $this->app->loadLang('testcase'); + $this->session->set('caseList', $this->app->getURI(true)); + + /* Set the browseType and moduleID. */ + $browseType = strtolower($browseType); + $moduleID = ($browseType == 'bymodule') ? (int)$param : 0; + + /* Get task and product info, set menu. */ + $task = $this->testtask->getById($taskID); + if(!$task) die(js::error($this->lang->notFound) . js::locate('back')); + $productID = $task->product; + $this->testtask->setMenu($this->products, $productID); + + if($browseType == 'bymodule' or $browseType == 'all') + { + $modules = ''; + if($moduleID) $modules = $this->loadModel('tree')->getAllChildID($moduleID); + $this->view->runs = $this->testtask->getRuns($taskID, $modules); + } + elseif($browseType == 'assignedtome') + { + $this->view->runs = $this->testtask->getUserRuns($taskID, $this->session->user->account); + } + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->cases; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->cases; + + $this->view->productID = $productID; + $this->view->productName = $this->products[$productID]; + $this->view->task = $task; + $this->view->users = $this->loadModel('user')->getPairs('noclosed'); + $this->view->moduleTree = $this->loadModel('tree')->getTreeMenu($productID, $viewType = 'case', $startModuleID = 0, array('treeModel', 'createTestTaskLink'), $extra = $taskID); + $this->view->browseType = $browseType; + $this->view->taskID = $taskID; + $this->view->moduleID = $moduleID; + $this->view->treeClass = $browseType == 'bymodule' ? '' : 'hidden'; + + $this->display(); + } + + /** + * Edit a test task. + * + * @param int $taskID + * @access public + * @return void + */ + public function edit($taskID) + { + if(!empty($_POST)) + { + $changes = $this->testtask->update($taskID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('testtask', $taskID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "taskID=$taskID"), 'parent')); + } + + /* Get task info. */ + $task = $this->testtask->getById($taskID); + $productID = $this->product->saveState($task->product, $this->products); + + /* Set menu. */ + $this->testtask->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->edit; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->edit; + + $this->view->task = $task; + $this->view->projects = $this->product->getProjectPairs($productID); + $this->view->builds = $this->loadModel('build')->getProductBuildPairs($productID); + $this->view->users = $this->loadModel('user')->getPairs(); + + $this->display(); + } + + /** + * Delete a test task. + * + * @param int $taskID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($taskID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->testtask->confirmDelete, inlink('delete', "taskID=$taskID&confirm=yes"))); + } + else + { + $task = $this->testtask->getByID($taskID); + $this->testtask->delete(TABLE_TESTTASK, $taskID); + die(js::locate(inlink('browse', "product=$task->product"), 'parent')); + } + } + + /** + * Link cases to a test task. + * + * @param int $taskID + * @access public + * @return void + */ + public function linkCase($taskID, $param = 'all', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + if(!empty($_POST)) + { + $this->testtask->linkCase($taskID); + $this->locate(inlink('cases', "taskID=$taskID")); + } + + /* Save session. */ + $this->session->set('caseList', $this->app->getURI(true)); + + /* Get task and product id. */ + $task = $this->testtask->getById($taskID); + $productID = $this->product->saveState($task->product, $this->products); + + /* Load pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + /* Build the search form. */ + $this->loadModel('testcase'); + $this->config->testcase->search['params']['product']['values']= array($productID => $this->products[$productID], 'all' => $this->lang->testcase->allProduct); + $this->config->testcase->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'case'); + $this->config->testcase->search['actionURL'] = inlink('linkcase', "taskID=$taskID"); + $this->view->searchForm = $this->fetch('search', 'buildForm', $this->config->testcase->search); + + /* Save session. */ + $this->testtask->setMenu($this->products, $productID); + + $this->view->header['title'] = $this->products[$productID] . $this->lang->colon . $this->lang->testtask->linkCase; + $this->view->position[] = html::a($this->createLink('testtask', 'browse', "productID=$productID"), $this->products[$productID]); + $this->view->position[] = $this->lang->testtask->linkCase; + + /* Get cases. */ + if($this->session->testcaseQuery == false) $this->session->set('testcaseQuery', ' 1 = 1'); + $query = str_replace("`product` = 'all'", '1', $this->session->testcaseQuery); // If search all product, replace product = all to 1=1 + $linkedCases = $this->dao->select('`case`')->from(TABLE_TESTRUN)->where('task')->eq($taskID)->fetchPairs('case'); + if($param == 'all') + { + $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) + ->andWhere('product')->eq($productID) + ->andWhere('id')->notIN($linkedCases) + ->andWhere('deleted')->eq(0) + ->orderBy('id desc') + ->page($pager) + ->fetchAll(); + } + if($param == 'bystory') + { + $stories = $this->dao->select('stories')->from(TABLE_BUILD)->where('id')->eq($task->build)->fetch('stories'); + + $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) + ->andWhere('product')->eq($productID) + ->beginIF($linkedCases)->andWhere('id')->notIN($linkedCases)->fi() + ->andWhere('story')->in($stories) + ->andWhere('deleted')->eq(0) + ->orderBy('id desc') + ->page($pager) + ->fetchAll(); + } + if($param == 'bybug') + { + $bugs = $this->dao->select('bugs')->from(TABLE_BUILD)->where('id')->eq($task->build)->fetch('bugs'); + $cases = $this->dao->select('*')->from(TABLE_CASE)->where($query) + ->andWhere('product')->eq($productID) + ->beginIF($linkedCases)->andWhere('id')->notIN($linkedCases)->fi() + ->andWhere('fromBug')->in($bugs) + ->andWhere('deleted')->eq(0) + ->orderBy('id desc') + ->page($pager) + ->fetchAll(); + } + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->cases = $cases; + $this->view->taskID = $taskID; + $this->view->pager = $pager; + + $this->display(); + } + + /** + * Remove a case from test task. + * + * @param int $rowID + * @access public + * @return void + */ + public function unlinkCase($rowID) + { + $this->dao->delete()->from(TABLE_TESTRUN)->where('id')->eq((int)$rowID)->exec(); + die(js::reload('parent')); + } + + /** + * Run case. + * + * @param int $runID + * @param String $extras others params, forexample, caseID=10, version=3 + * @access public + * @return void + */ + public function runCase($runID, $caseID = 0, $version = 0) + { + if(!empty($_POST)) + { + $this->testtask->createResult($runID); + if(dao::isError()) die(js::error(dao::getError())); + echo js::reload('parent'); + die(js::closeWindow()); + } + + if(!$caseID) $run = $this->testtask->getRunById($runID); + if($caseID) $run->case = $this->loadModel('testcase')->getById($caseID, $version); + + $this->view->run = $run; + + die($this->display()); + } + + /** + * View test results of a test run. + * + * @param int $runID + * @param int $caseID + * @access public + * @return void + */ + public function results($runID, $caseID = 0, $version = 0) + { + if($caseID) + { + $this->view->case = $this->loadModel('testcase')->getByID($caseID, $version); + $this->view->results = $this->testtask->getResults(0, $caseID); + } + else + { + $this->view->case = $this->testtask->getRunById($runID)->case; + $this->view->results = $this->testtask->getResults($runID); + } + $this->view->users = $this->loadModel('user')->getPairs('noclosed, noletter'); + + die($this->display()); + } + + /** + * Batch assign cases. + * + * @param int $taskID + * @access public + * @return void + */ + public function batchAssign($taskID) + { + $this->dao->update(TABLE_TESTRUN) + ->set('assignedTo')->eq($this->post->assignedTo) + ->where('task')->eq((int)$taskID) + ->andWhere('`case`')->in($this->post->cases) + ->exec(); + die(js::reload('parent')); + } +} diff --git a/module/testtask/lang/en.php b/module/testtask/lang/en.php index 55e200cc19..96a94b267d 100644 --- a/module/testtask/lang/en.php +++ b/module/testtask/lang/en.php @@ -1,66 +1,66 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->testtask->index = "Index"; -$lang->testtask->create = "Create"; -$lang->testtask->delete = "Delete"; -$lang->testtask->view = "Info"; -$lang->testtask->edit = "Edit"; -$lang->testtask->browse = "Browse"; -$lang->testtask->linkCase = "Link case"; -$lang->testtask->linkCaseAB = "Link"; -$lang->testtask->unlinkCase = "Remove"; -$lang->testtask->batchAssign = "Batch Assign"; -$lang->testtask->runCase = "Run"; -$lang->testtask->results = "Result"; -$lang->testtask->createBug = "Create bug"; -$lang->testtask->assign = 'Assign'; -$lang->testtask->cases = 'Cases'; - -$lang->testtask->common = 'Test task'; -$lang->testtask->id = 'ID'; -$lang->testtask->product = 'Product'; -$lang->testtask->project = 'Project'; -$lang->testtask->build = 'Build'; -$lang->testtask->owner = 'Owner'; -$lang->testtask->name = 'Name'; -$lang->testtask->begin = 'Begin'; -$lang->testtask->end = 'End'; -$lang->testtask->desc = 'Desc'; -$lang->testtask->status = 'Status'; -$lang->testtask->assignedTo = 'Assigned to'; -$lang->testtask->linkVersion = 'Link(version)'; -$lang->testtask->lastRunAccount = "Run account"; -$lang->testtask->lastRunTime = 'Last run'; -$lang->testtask->lastRunResult = 'Last result'; - -$lang->testtask->statusList['wait'] = 'Pending'; -$lang->testtask->statusList['doing'] = 'In progress'; -$lang->testtask->statusList['done'] = 'Done'; -$lang->testtask->statusList['blocked'] = 'Blocked'; - -$lang->testtask->unlinkedCases = 'Unlinked cases'; -$lang->testtask->linkedCases = 'Linked cases'; -$lang->testtask->linkByStory = 'Link by story'; -$lang->testtask->linkByBug = 'Link by bug'; -$lang->testtask->confirmDelete = 'Are you sure to delete this test task?'; -$lang->testtask->passAll = 'Pass all'; -$lang->testtask->pass = 'Pass'; -$lang->testtask->fail = 'Fail'; - -$lang->testtask->byModule = 'By module'; -$lang->testtask->assignedToMe = 'Assgined to me'; -$lang->testtask->allCases = 'All Cases'; - -$lang->testtask->lblCases = 'Case list'; -$lang->testtask->lblUnlinkCase = 'Remove case'; -$lang->testtask->lblRunCase = 'Run'; -$lang->testtask->lblResults = 'Result'; + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->testtask->index = "Index"; +$lang->testtask->create = "Create"; +$lang->testtask->delete = "Delete"; +$lang->testtask->view = "Info"; +$lang->testtask->edit = "Edit"; +$lang->testtask->browse = "Browse"; +$lang->testtask->linkCase = "Link case"; +$lang->testtask->linkCaseAB = "Link"; +$lang->testtask->unlinkCase = "Remove"; +$lang->testtask->batchAssign = "Batch Assign"; +$lang->testtask->runCase = "Run"; +$lang->testtask->results = "Result"; +$lang->testtask->createBug = "Create bug"; +$lang->testtask->assign = 'Assign'; +$lang->testtask->cases = 'Cases'; + +$lang->testtask->common = 'Test task'; +$lang->testtask->id = 'ID'; +$lang->testtask->product = 'Product'; +$lang->testtask->project = 'Project'; +$lang->testtask->build = 'Build'; +$lang->testtask->owner = 'Owner'; +$lang->testtask->name = 'Name'; +$lang->testtask->begin = 'Begin'; +$lang->testtask->end = 'End'; +$lang->testtask->desc = 'Desc'; +$lang->testtask->status = 'Status'; +$lang->testtask->assignedTo = 'Assigned to'; +$lang->testtask->linkVersion = 'Link(version)'; +$lang->testtask->lastRunAccount = "Run account"; +$lang->testtask->lastRunTime = 'Last run'; +$lang->testtask->lastRunResult = 'Last result'; + +$lang->testtask->statusList['wait'] = 'Pending'; +$lang->testtask->statusList['doing'] = 'In progress'; +$lang->testtask->statusList['done'] = 'Done'; +$lang->testtask->statusList['blocked'] = 'Blocked'; + +$lang->testtask->unlinkedCases = 'Unlinked cases'; +$lang->testtask->linkedCases = 'Linked cases'; +$lang->testtask->linkByStory = 'Link by story'; +$lang->testtask->linkByBug = 'Link by bug'; +$lang->testtask->confirmDelete = 'Are you sure to delete this test task?'; +$lang->testtask->passAll = 'Pass all'; +$lang->testtask->pass = 'Pass'; +$lang->testtask->fail = 'Fail'; + +$lang->testtask->byModule = 'By module'; +$lang->testtask->assignedToMe = 'Assgined to me'; +$lang->testtask->allCases = 'All Cases'; + +$lang->testtask->lblCases = 'Case list'; +$lang->testtask->lblUnlinkCase = 'Remove case'; +$lang->testtask->lblRunCase = 'Run'; +$lang->testtask->lblResults = 'Result'; diff --git a/module/testtask/lang/zh-cn.php b/module/testtask/lang/zh-cn.php index 76961d8524..6fd88ba3b5 100644 --- a/module/testtask/lang/zh-cn.php +++ b/module/testtask/lang/zh-cn.php @@ -1,66 +1,66 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->testtask->index = "测试任务首页"; -$lang->testtask->create = "创建测试任务"; -$lang->testtask->delete = "删除测试任务"; -$lang->testtask->view = "详情"; -$lang->testtask->edit = "编辑测试任务"; -$lang->testtask->browse = "测试任务列表"; -$lang->testtask->linkCase = "关联用例"; -$lang->testtask->linkCaseAB = "关联"; -$lang->testtask->unlinkCase = "移除"; -$lang->testtask->batchAssign = "批量指派"; -$lang->testtask->runCase = "执行"; -$lang->testtask->results = "结果"; -$lang->testtask->createBug = "创建Bug"; -$lang->testtask->assign = '指派'; -$lang->testtask->cases = '用例'; - -$lang->testtask->common = '测试任务'; -$lang->testtask->id = '任务编号'; -$lang->testtask->product = '所属产品'; -$lang->testtask->project = '所属项目'; -$lang->testtask->build = 'Build'; -$lang->testtask->owner = '负责人'; -$lang->testtask->name = '任务名称'; -$lang->testtask->begin = '开始日期'; -$lang->testtask->end = '结束日期'; -$lang->testtask->desc = '任务描述'; -$lang->testtask->status = '当前状态'; -$lang->testtask->assignedTo = '指派给'; -$lang->testtask->linkVersion = '关联(版本)'; -$lang->testtask->lastRunAccount = '最后执行人'; -$lang->testtask->lastRunTime = '最后执行时间'; -$lang->testtask->lastRunResult = '最终结果'; - -$lang->testtask->statusList['wait'] = '未开始'; -$lang->testtask->statusList['doing'] = '进行中'; -$lang->testtask->statusList['done'] = '已完成'; -$lang->testtask->statusList['blocked'] = '被阻塞'; - -$lang->testtask->unlinkedCases = '未关联用例列表'; -$lang->testtask->linkedCases = '已关联用例列表'; -$lang->testtask->linkByStory = '按需求关联用例'; -$lang->testtask->linkByBug = '按Bug关联用例'; -$lang->testtask->confirmDelete = '您确认要删除该测试任务吗?'; -$lang->testtask->passAll = '全部通过'; -$lang->testtask->pass = '通过'; -$lang->testtask->fail = '失败'; - -$lang->testtask->byModule = '按模块'; -$lang->testtask->assignedToMe = '指派给我'; -$lang->testtask->allCases = '所有Case'; - -$lang->testtask->lblCases = '用例列表'; -$lang->testtask->lblUnlinkCase = '移除用例'; -$lang->testtask->lblRunCase = '执行用例'; -$lang->testtask->lblResults = '执行结果'; + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->testtask->index = "测试任务首页"; +$lang->testtask->create = "创建测试任务"; +$lang->testtask->delete = "删除测试任务"; +$lang->testtask->view = "详情"; +$lang->testtask->edit = "编辑测试任务"; +$lang->testtask->browse = "测试任务列表"; +$lang->testtask->linkCase = "关联用例"; +$lang->testtask->linkCaseAB = "关联"; +$lang->testtask->unlinkCase = "移除"; +$lang->testtask->batchAssign = "批量指派"; +$lang->testtask->runCase = "执行"; +$lang->testtask->results = "结果"; +$lang->testtask->createBug = "创建Bug"; +$lang->testtask->assign = '指派'; +$lang->testtask->cases = '用例'; + +$lang->testtask->common = '测试任务'; +$lang->testtask->id = '任务编号'; +$lang->testtask->product = '所属产品'; +$lang->testtask->project = '所属项目'; +$lang->testtask->build = 'Build'; +$lang->testtask->owner = '负责人'; +$lang->testtask->name = '任务名称'; +$lang->testtask->begin = '开始日期'; +$lang->testtask->end = '结束日期'; +$lang->testtask->desc = '任务描述'; +$lang->testtask->status = '当前状态'; +$lang->testtask->assignedTo = '指派给'; +$lang->testtask->linkVersion = '关联(版本)'; +$lang->testtask->lastRunAccount = '最后执行人'; +$lang->testtask->lastRunTime = '最后执行时间'; +$lang->testtask->lastRunResult = '最终结果'; + +$lang->testtask->statusList['wait'] = '未开始'; +$lang->testtask->statusList['doing'] = '进行中'; +$lang->testtask->statusList['done'] = '已完成'; +$lang->testtask->statusList['blocked'] = '被阻塞'; + +$lang->testtask->unlinkedCases = '未关联用例列表'; +$lang->testtask->linkedCases = '已关联用例列表'; +$lang->testtask->linkByStory = '按需求关联用例'; +$lang->testtask->linkByBug = '按Bug关联用例'; +$lang->testtask->confirmDelete = '您确认要删除该测试任务吗?'; +$lang->testtask->passAll = '全部通过'; +$lang->testtask->pass = '通过'; +$lang->testtask->fail = '失败'; + +$lang->testtask->byModule = '按模块'; +$lang->testtask->assignedToMe = '指派给我'; +$lang->testtask->allCases = '所有Case'; + +$lang->testtask->lblCases = '用例列表'; +$lang->testtask->lblUnlinkCase = '移除用例'; +$lang->testtask->lblRunCase = '执行用例'; +$lang->testtask->lblResults = '执行结果'; diff --git a/module/testtask/lang/zh-tw.php b/module/testtask/lang/zh-tw.php index d64c5a71ab..0e8f8a4e1b 100644 --- a/module/testtask/lang/zh-tw.php +++ b/module/testtask/lang/zh-tw.php @@ -1,66 +1,66 @@ - - * @package testtask - * @version $Id: zh-tw.php 2570 2012-02-10 01:31:52Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->testtask->index = "測試任務首頁"; -$lang->testtask->create = "創建測試任務"; -$lang->testtask->delete = "刪除測試任務"; -$lang->testtask->view = "詳情"; -$lang->testtask->edit = "編輯測試任務"; -$lang->testtask->browse = "測試任務列表"; -$lang->testtask->linkCase = "關聯用例"; -$lang->testtask->linkCaseAB = "關聯"; -$lang->testtask->unlinkCase = "移除"; -$lang->testtask->batchAssign = "批量指派"; -$lang->testtask->runCase = "執行"; -$lang->testtask->results = "結果"; -$lang->testtask->createBug = "創建Bug"; -$lang->testtask->assign = '指派'; -$lang->testtask->cases = '用例'; - -$lang->testtask->common = '測試任務'; -$lang->testtask->id = '任務編號'; -$lang->testtask->product = '所屬產品'; -$lang->testtask->project = '所屬項目'; -$lang->testtask->build = 'Build'; -$lang->testtask->owner = '負責人'; -$lang->testtask->name = '任務名稱'; -$lang->testtask->begin = '開始日期'; -$lang->testtask->end = '結束日期'; -$lang->testtask->desc = '任務描述'; -$lang->testtask->status = '當前狀態'; -$lang->testtask->assignedTo = '指派給'; -$lang->testtask->linkVersion = '關聯(版本)'; -$lang->testtask->lastRunAccount = '最後執行人'; -$lang->testtask->lastRunTime = '最後執行時間'; -$lang->testtask->lastRunResult = '最終結果'; - -$lang->testtask->statusList['wait'] = '未開始'; -$lang->testtask->statusList['doing'] = '進行中'; -$lang->testtask->statusList['done'] = '已完成'; -$lang->testtask->statusList['blocked'] = '被阻塞'; - -$lang->testtask->unlinkedCases = '未關聯用例列表'; -$lang->testtask->linkedCases = '已關聯用例列表'; -$lang->testtask->linkByStory = '按需求關聯用例'; -$lang->testtask->linkByBug = '按Bug關聯用例'; -$lang->testtask->confirmDelete = '您確認要刪除該測試任務嗎?'; -$lang->testtask->passAll = '全部通過'; -$lang->testtask->pass = '通過'; -$lang->testtask->fail = '失敗'; - -$lang->testtask->byModule = '按模組'; -$lang->testtask->assignedToMe = '指派給我'; -$lang->testtask->allCases = '所有Case'; - -$lang->testtask->lblCases = '用例列表'; -$lang->testtask->lblUnlinkCase = '移除用例'; -$lang->testtask->lblRunCase = '執行用例'; -$lang->testtask->lblResults = '執行結果'; + + * @package testtask + * @version $Id: zh-tw.php 2570 2012-02-10 01:31:52Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->testtask->index = "測試任務首頁"; +$lang->testtask->create = "創建測試任務"; +$lang->testtask->delete = "刪除測試任務"; +$lang->testtask->view = "詳情"; +$lang->testtask->edit = "編輯測試任務"; +$lang->testtask->browse = "測試任務列表"; +$lang->testtask->linkCase = "關聯用例"; +$lang->testtask->linkCaseAB = "關聯"; +$lang->testtask->unlinkCase = "移除"; +$lang->testtask->batchAssign = "批量指派"; +$lang->testtask->runCase = "執行"; +$lang->testtask->results = "結果"; +$lang->testtask->createBug = "創建Bug"; +$lang->testtask->assign = '指派'; +$lang->testtask->cases = '用例'; + +$lang->testtask->common = '測試任務'; +$lang->testtask->id = '任務編號'; +$lang->testtask->product = '所屬產品'; +$lang->testtask->project = '所屬項目'; +$lang->testtask->build = 'Build'; +$lang->testtask->owner = '負責人'; +$lang->testtask->name = '任務名稱'; +$lang->testtask->begin = '開始日期'; +$lang->testtask->end = '結束日期'; +$lang->testtask->desc = '任務描述'; +$lang->testtask->status = '當前狀態'; +$lang->testtask->assignedTo = '指派給'; +$lang->testtask->linkVersion = '關聯(版本)'; +$lang->testtask->lastRunAccount = '最後執行人'; +$lang->testtask->lastRunTime = '最後執行時間'; +$lang->testtask->lastRunResult = '最終結果'; + +$lang->testtask->statusList['wait'] = '未開始'; +$lang->testtask->statusList['doing'] = '進行中'; +$lang->testtask->statusList['done'] = '已完成'; +$lang->testtask->statusList['blocked'] = '被阻塞'; + +$lang->testtask->unlinkedCases = '未關聯用例列表'; +$lang->testtask->linkedCases = '已關聯用例列表'; +$lang->testtask->linkByStory = '按需求關聯用例'; +$lang->testtask->linkByBug = '按Bug關聯用例'; +$lang->testtask->confirmDelete = '您確認要刪除該測試任務嗎?'; +$lang->testtask->passAll = '全部通過'; +$lang->testtask->pass = '通過'; +$lang->testtask->fail = '失敗'; + +$lang->testtask->byModule = '按模組'; +$lang->testtask->assignedToMe = '指派給我'; +$lang->testtask->allCases = '所有Case'; + +$lang->testtask->lblCases = '用例列表'; +$lang->testtask->lblUnlinkCase = '移除用例'; +$lang->testtask->lblRunCase = '執行用例'; +$lang->testtask->lblResults = '執行結果'; diff --git a/module/testtask/model.php b/module/testtask/model.php index c052c6a173..8a4ebec113 100644 --- a/module/testtask/model.php +++ b/module/testtask/model.php @@ -1,345 +1,345 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> -loadModel('product')->setMenu($products, $productID); - $selectHtml = $this->product->select($products, $productID, 'testtask', 'browse'); - foreach($this->lang->testtask->menu as $key => $value) - { - $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow: $productID; - common::setMenuVars($this->lang->testtask->menu, $key, $replace); - } - } - - /** - * Create a test task. - * - * @param int $productID - * @access public - * @return void - */ - function create() - { - $task = fixer::input('post') - ->stripTags('name') - ->get(); - $this->dao->insert(TABLE_TESTTASK)->data($task)->autoCheck()->batchcheck($this->config->testtask->create->requiredFields, 'notempty')->exec(); - if(!dao::isError()) return $this->dao->lastInsertID(); - } - - /** - * Get test tasks of a product. - * - * @param int $productID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getProductTasks($productID, $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('t1.*, t2.name AS productName, t3.name AS projectName, t4.name AS buildName') - ->from(TABLE_TESTTASK)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') - ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t1.project = t3.id') - ->leftJoin(TABLE_BUILD)->alias('t4')->on('t1.build = t4.id') - ->where('t1.product')->eq((int)$productID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - } - - /** - * Get test tasks of a project. - * - * @param int $projectID - * @param string $orderBy - * @param object $pager - * @access public - * @return array - */ - public function getProjectTasks($projectID, $orderBy = 'id_desc', $pager = null) - { - return $this->dao->select('t1.*, t2.name AS buildName') - ->from(TABLE_TESTTASK)->alias('t1') - ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.build = t2.id') - ->where('t1.project')->eq((int)$projectID) - ->andWhere('t1.deleted')->eq(0) - ->orderBy($orderBy) - ->page($pager) - ->fetchAll(); - } - - /** - * Get test task info by id. - * - * @param int $taskID - * @access public - * @return void - */ - public function getById($taskID) - { - $task = $this->dao->select('t1.*, t2.name AS productName, t3.name AS projectName, t4.name AS buildName') - ->from(TABLE_TESTTASK)->alias('t1') - ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') - ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t1.project = t3.id') - ->leftJoin(TABLE_BUILD)->alias('t4')->on('t1.build = t4.id') - ->where('t1.id')->eq((int)$taskID)->fetch(); - $task->desc = $this->loadModel('file')->setImgSize($task->desc); - return $task; - } - - /** - * Get test tasks by user. - * - * @param string $account - * @access public - * @return array - */ - public function getByUser($account) - { - return $this->dao->select('t1.*, t2.name AS projectName, t3.name AS buildName') - ->from(TABLE_TESTTASK)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id') - ->where('t1.deleted')->eq(0) - ->andWhere('t1.owner')->eq($account) - ->orderBy('id desc') - ->fetchAll(); - } - - /** - * Update a test task. - * - * @param int $taskID - * @access public - * @return void - */ - public function update($taskID) - { - $oldTask = $this->getById($taskID); - $task = fixer::input('post')->stripTags('name')->get(); - $this->dao->update(TABLE_TESTTASK)->data($task)->autoCheck()->batchcheck($this->config->testtask->edit->requiredFields, 'notempty')->where('id')->eq($taskID)->exec(); - if(!dao::isError()) return common::createChanges($oldTask, $task); - } - - /** - * Link cases. - * - * @param int $taskID - * @access public - * @return void - */ - public function linkCase($taskID) - { - if($this->post->cases == false) return; - foreach($this->post->cases as $caseID) - { - $row->task = $taskID; - $row->case = $caseID; - $row->version = $this->post->versions[$caseID]; - $row->assignedTo = ''; - $row->status = 'wait'; - $this->dao->replace(TABLE_TESTRUN)->data($row)->exec(); - } - } - - /** - * Get test runs of a test task. - * - * @param int $taskID - * @param int $moduleID - * @access public - * @return array - */ - public function getRuns($taskID, $moduleID) - { - return $this->dao->select('t2.*,t1.*')->from(TABLE_TESTRUN)->alias('t1') - ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') - ->where('t1.task')->eq((int)$taskID) - ->beginIF($moduleID)->andWhere('t2.module')->in($moduleID)->fi() - ->fetchAll(); - } - - /** - * Get test runs of a user. - * - * @param int $taskID - * @param int $user - * @access public - * @return array - */ - public function getUserRuns($taskID, $user) - { - return $this->dao->select('t2.*,t1.*')->from(TABLE_TESTRUN)->alias('t1') - ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') - ->where('t1.task')->eq((int)$taskID) - ->andWhere('t1.assignedTo')->eq($user) - ->fetchAll(); - } - - /** - * Get info of a test run. - * - * @param int $runID - * @access public - * @return void - */ - public function getRunById($runID) - { - $testRun = $this->dao->findById($runID)->from(TABLE_TESTRUN)->fetch(); - $testRun->case = $this->loadModel('testcase')->getById($testRun->case, $testRun->version); - return $testRun; - } - - /** - * Create test result - * - * @param int $runID - * @access public - * @return void - */ - public function createResult($runID = 0) - { - /* Compute the test result. - * - * 1. if there result in the post, use it. - * 2. if no result, set default is pass. - * 3. then check the steps to compute result. - * - * */ - $caseResult = $this->post->result ? $this->post->result : 'pass'; - if(isset($_POST['passall']) and $this->post->passall == false) - { - if($this->post->steps) - { - foreach($this->post->steps as $stepID => $stepResult) - { - if($stepResult != 'pass' and $stepResult != 'n/a') - { - $caseResult = $stepResult; - break; - } - } - } - } - - /* Create result of every step. */ - if($this->post->steps) - { - foreach($this->post->steps as $stepID =>$stepResult) - { - $step['result'] = $stepResult; - $step['real'] = $this->post->reals[$stepID]; - $stepResults[$stepID] = $step; - } - } - else - { - $stepResults = array(); - } - - /* Insert into testResult table. */ - $now = helper::now(); - $result = fixer::input('post') - ->add('run', $runID) - ->add('caseResult', $caseResult) - ->setForce('stepResults', serialize($stepResults)) - ->add('lastRunner', $this->app->user->account) - ->add('date', $now) - ->remove('steps,reals,passall,result') - ->get(); - $this->dao->insert(TABLE_TESTRESULT)->data($result)->autoCheck()->exec(); - $this->dao->update(TABLE_CASE)->set('lastRunner')->eq($this->app->user->account)->set('lastRunDate')->eq($now)->set('lastRunResult')->eq($caseResult)->where('id')->eq($this->post->case)->exec(); - - if($runID) - { - /* Update testRun's status. */ - if(!dao::isError()) - { - $runStatus = $caseResult == 'blocked' ? 'blocked' : 'done'; - $this->dao->update(TABLE_TESTRUN) - ->set('lastRunResult')->eq($caseResult) - ->set('status')->eq($runStatus) - ->set('lastRunner')->eq($this->app->user->account) - ->set('lastRunDate')->eq($now) - ->where('id')->eq($runID) - ->exec(); - } - } - } - - /** - * Get results by runID or caseID - * - * @param int $runID - * @param int $caseID - * @access public - * @return array - */ - public function getResults($runID, $caseID = 0) - { - if($caseID > 0) - { - $results = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('id desc')->fetchAll('id'); - } - else - { - $results = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->fetchAll('id'); - } - - if(!$results) return array(); - - $relatedVersions = array(); - foreach($results as $result) - { - $relatedVersions[] = $result->version; - $runCaseID = $result->case; - } - $relatedVersions = array_unique($relatedVersions); - - $relatedSteps = $this->dao->select('*')->from(TABLE_CASESTEP) - ->beginIF($caseID)->where('`case`')->eq($caseID)->fi() - ->beginIF($runID)->where('`case`')->eq($runCaseID)->fi() - ->andWhere('version')->in($relatedVersions) - ->fetchAll(); - - foreach($results as $resultID => $result) - { - $result->stepResults = unserialize($result->stepResults); - $results[$resultID] = $result; - - foreach($relatedSteps as $key => $step) - { - if($result->version == $step->version) - { - $result->stepResults[$step->id]['desc'] = $step->desc; - $result->stepResults[$step->id]['expect'] = $step->expect; - } - } - } - return $results; - } -} + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> +loadModel('product')->setMenu($products, $productID); + $selectHtml = $this->product->select($products, $productID, 'testtask', 'browse'); + foreach($this->lang->testtask->menu as $key => $value) + { + $replace = ($key == 'product') ? $selectHtml . $this->lang->arrow: $productID; + common::setMenuVars($this->lang->testtask->menu, $key, $replace); + } + } + + /** + * Create a test task. + * + * @param int $productID + * @access public + * @return void + */ + function create() + { + $task = fixer::input('post') + ->stripTags('name') + ->get(); + $this->dao->insert(TABLE_TESTTASK)->data($task)->autoCheck()->batchcheck($this->config->testtask->create->requiredFields, 'notempty')->exec(); + if(!dao::isError()) return $this->dao->lastInsertID(); + } + + /** + * Get test tasks of a product. + * + * @param int $productID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getProductTasks($productID, $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('t1.*, t2.name AS productName, t3.name AS projectName, t4.name AS buildName') + ->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t1.project = t3.id') + ->leftJoin(TABLE_BUILD)->alias('t4')->on('t1.build = t4.id') + ->where('t1.product')->eq((int)$productID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } + + /** + * Get test tasks of a project. + * + * @param int $projectID + * @param string $orderBy + * @param object $pager + * @access public + * @return array + */ + public function getProjectTasks($projectID, $orderBy = 'id_desc', $pager = null) + { + return $this->dao->select('t1.*, t2.name AS buildName') + ->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.build = t2.id') + ->where('t1.project')->eq((int)$projectID) + ->andWhere('t1.deleted')->eq(0) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll(); + } + + /** + * Get test task info by id. + * + * @param int $taskID + * @access public + * @return void + */ + public function getById($taskID) + { + $task = $this->dao->select('t1.*, t2.name AS productName, t3.name AS projectName, t4.name AS buildName') + ->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id') + ->leftJoin(TABLE_PROJECT)->alias('t3')->on('t1.project = t3.id') + ->leftJoin(TABLE_BUILD)->alias('t4')->on('t1.build = t4.id') + ->where('t1.id')->eq((int)$taskID)->fetch(); + $task->desc = $this->loadModel('file')->setImgSize($task->desc); + return $task; + } + + /** + * Get test tasks by user. + * + * @param string $account + * @access public + * @return array + */ + public function getByUser($account) + { + return $this->dao->select('t1.*, t2.name AS projectName, t3.name AS buildName') + ->from(TABLE_TESTTASK)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id') + ->where('t1.deleted')->eq(0) + ->andWhere('t1.owner')->eq($account) + ->orderBy('id desc') + ->fetchAll(); + } + + /** + * Update a test task. + * + * @param int $taskID + * @access public + * @return void + */ + public function update($taskID) + { + $oldTask = $this->getById($taskID); + $task = fixer::input('post')->stripTags('name')->get(); + $this->dao->update(TABLE_TESTTASK)->data($task)->autoCheck()->batchcheck($this->config->testtask->edit->requiredFields, 'notempty')->where('id')->eq($taskID)->exec(); + if(!dao::isError()) return common::createChanges($oldTask, $task); + } + + /** + * Link cases. + * + * @param int $taskID + * @access public + * @return void + */ + public function linkCase($taskID) + { + if($this->post->cases == false) return; + foreach($this->post->cases as $caseID) + { + $row->task = $taskID; + $row->case = $caseID; + $row->version = $this->post->versions[$caseID]; + $row->assignedTo = ''; + $row->status = 'wait'; + $this->dao->replace(TABLE_TESTRUN)->data($row)->exec(); + } + } + + /** + * Get test runs of a test task. + * + * @param int $taskID + * @param int $moduleID + * @access public + * @return array + */ + public function getRuns($taskID, $moduleID) + { + return $this->dao->select('t2.*,t1.*')->from(TABLE_TESTRUN)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') + ->where('t1.task')->eq((int)$taskID) + ->beginIF($moduleID)->andWhere('t2.module')->in($moduleID)->fi() + ->fetchAll(); + } + + /** + * Get test runs of a user. + * + * @param int $taskID + * @param int $user + * @access public + * @return array + */ + public function getUserRuns($taskID, $user) + { + return $this->dao->select('t2.*,t1.*')->from(TABLE_TESTRUN)->alias('t1') + ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id') + ->where('t1.task')->eq((int)$taskID) + ->andWhere('t1.assignedTo')->eq($user) + ->fetchAll(); + } + + /** + * Get info of a test run. + * + * @param int $runID + * @access public + * @return void + */ + public function getRunById($runID) + { + $testRun = $this->dao->findById($runID)->from(TABLE_TESTRUN)->fetch(); + $testRun->case = $this->loadModel('testcase')->getById($testRun->case, $testRun->version); + return $testRun; + } + + /** + * Create test result + * + * @param int $runID + * @access public + * @return void + */ + public function createResult($runID = 0) + { + /* Compute the test result. + * + * 1. if there result in the post, use it. + * 2. if no result, set default is pass. + * 3. then check the steps to compute result. + * + * */ + $caseResult = $this->post->result ? $this->post->result : 'pass'; + if(isset($_POST['passall']) and $this->post->passall == false) + { + if($this->post->steps) + { + foreach($this->post->steps as $stepID => $stepResult) + { + if($stepResult != 'pass' and $stepResult != 'n/a') + { + $caseResult = $stepResult; + break; + } + } + } + } + + /* Create result of every step. */ + if($this->post->steps) + { + foreach($this->post->steps as $stepID =>$stepResult) + { + $step['result'] = $stepResult; + $step['real'] = $this->post->reals[$stepID]; + $stepResults[$stepID] = $step; + } + } + else + { + $stepResults = array(); + } + + /* Insert into testResult table. */ + $now = helper::now(); + $result = fixer::input('post') + ->add('run', $runID) + ->add('caseResult', $caseResult) + ->setForce('stepResults', serialize($stepResults)) + ->add('lastRunner', $this->app->user->account) + ->add('date', $now) + ->remove('steps,reals,passall,result') + ->get(); + $this->dao->insert(TABLE_TESTRESULT)->data($result)->autoCheck()->exec(); + $this->dao->update(TABLE_CASE)->set('lastRunner')->eq($this->app->user->account)->set('lastRunDate')->eq($now)->set('lastRunResult')->eq($caseResult)->where('id')->eq($this->post->case)->exec(); + + if($runID) + { + /* Update testRun's status. */ + if(!dao::isError()) + { + $runStatus = $caseResult == 'blocked' ? 'blocked' : 'done'; + $this->dao->update(TABLE_TESTRUN) + ->set('lastRunResult')->eq($caseResult) + ->set('status')->eq($runStatus) + ->set('lastRunner')->eq($this->app->user->account) + ->set('lastRunDate')->eq($now) + ->where('id')->eq($runID) + ->exec(); + } + } + } + + /** + * Get results by runID or caseID + * + * @param int $runID + * @param int $caseID + * @access public + * @return array + */ + public function getResults($runID, $caseID = 0) + { + if($caseID > 0) + { + $results = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('`case`')->eq($caseID)->orderBy('id desc')->fetchAll('id'); + } + else + { + $results = $this->dao->select('*')->from(TABLE_TESTRESULT)->where('run')->eq($runID)->orderBy('id desc')->fetchAll('id'); + } + + if(!$results) return array(); + + $relatedVersions = array(); + foreach($results as $result) + { + $relatedVersions[] = $result->version; + $runCaseID = $result->case; + } + $relatedVersions = array_unique($relatedVersions); + + $relatedSteps = $this->dao->select('*')->from(TABLE_CASESTEP) + ->beginIF($caseID)->where('`case`')->eq($caseID)->fi() + ->beginIF($runID)->where('`case`')->eq($runCaseID)->fi() + ->andWhere('version')->in($relatedVersions) + ->fetchAll(); + + foreach($results as $resultID => $result) + { + $result->stepResults = unserialize($result->stepResults); + $results[$resultID] = $result; + + foreach($relatedSteps as $key => $step) + { + if($result->version == $step->version) + { + $result->stepResults[$step->id]['desc'] = $step->desc; + $result->stepResults[$step->id]['expect'] = $step->expect; + } + } + } + return $results; + } +} diff --git a/module/testtask/view/browse.html.php b/module/testtask/view/browse.html.php index a383b9e5d8..5f1dd9d7ff 100644 --- a/module/testtask/view/browse.html.php +++ b/module/testtask/view/browse.html.php @@ -1,56 +1,56 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          testtask->browse;?>
          -
          testtask->create);?>
          -
          idAB;?>testtask->name;?>testtask->project;?>testtask->build;?>testtask->owner;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          id"), sprintf('%03d', $task->id));?>id"), $task->name);?>projectName?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>owner];?>begin?>end?>testtask->statusList[$task->status];?> - id", $lang->testtask->cases); - common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); - common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); - common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); - ?> -
          - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          testtask->browse;?>
          +
          testtask->create);?>
          +
          idAB;?>testtask->name;?>testtask->project;?>testtask->build;?>testtask->owner;?>testtask->begin;?>testtask->end;?>statusAB;?>actions;?>
          id"), sprintf('%03d', $task->id));?>id"), $task->name);?>projectName?>build == 'trunk' ? print('Trunk') : print(html::a($this->createLink('build', 'view', "buildID=$task->build"), $task->buildName));?>owner];?>begin?>end?>testtask->statusList[$task->status];?> + id", $lang->testtask->cases); + common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); + common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); + common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); + ?> +
          + diff --git a/module/testtask/view/cases.html.php b/module/testtask/view/cases.html.php index adab7c5a9b..c59497df55 100644 --- a/module/testtask/view/cases.html.php +++ b/module/testtask/view/cases.html.php @@ -1,101 +1,101 @@ - - * @package case - * @version $Id: view.html.php 594 2010-03-27 13:44:07Z wwccss $ - * @link http://www.zentao.net - */ -?> - - - - - -
          -
          - " . $lang->testtask->byModule . " "; - echo "" . html::a($this->inlink('cases', "taskID=$taskID&browseType=all¶m=0"), $lang->testtask->allCases) . ""; - echo "" . html::a($this->inlink('cases', "taskID=$taskID&browseType=assignedtome¶m=0"), $lang->testtask->assignedToMe) . ""; - ?> -
          -
          - id", $lang->testtask->linkCase); - echo html::a($this->session->testtaskList, $lang->goback); - ?> -
          -
          - - - - - - - -
          -
          -
          -
          -
          id");?>' target='hiddenwin'> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          idAB;?>priAB;?>testcase->title;?>testcase->type;?>testtask->assignedTo;?>testtask->lastRunAccount;?>testtask->lastRunTime;?>testtask->lastRunResult;?>statusAB;?>actions;?>
          case' /> "; printf('%03d', $run->case);?>pri?>createLink('testcase', 'view', "caseID=$run->case&version=$run->version"), $run->title, '_blank');?> - testcase->typeList[$run->type];?>assignedTo]; echo substr($assignedTo, strpos($assignedTo, ':') + 1);?>lastRunner]; echo substr($lastRunner, strpos($lastRunner, ':') + 1);?>lastRunDate)) echo date(DT_MONTHTIME1, strtotime($run->lastRunDate));?>lastRunResult) echo $lang->testcase->resultList[$run->lastRunResult];?>testtask->statusList[$run->status];?> - id", $lang->testtask->runCase, '', 'class="iframe"'); - common::printLink('testtask', 'results', "id=$run->id", $lang->testtask->results, '', 'class="iframe"'); - common::printLink('testtask', 'unlinkcase', "id=$run->id", $lang->testtask->unlinkCase, 'hiddenwin'); - if($run->lastRunResult == 'fail') common::printLink('bug', 'create', "product=$productID&extra=projectID=$task->project,buildID=$task->build,caseID=$run->case,runID=$run->id", $lang->testtask->createBug); - ?> -
          - - - - - -
          " . $lang->selectAll;?> - testtask->assign); - ?> -
          -
          -
          - + + * @package case + * @version $Id: view.html.php 594 2010-03-27 13:44:07Z wwccss $ + * @link http://www.zentao.net + */ +?> + + + + + +
          +
          + " . $lang->testtask->byModule . " "; + echo "" . html::a($this->inlink('cases', "taskID=$taskID&browseType=all¶m=0"), $lang->testtask->allCases) . ""; + echo "" . html::a($this->inlink('cases', "taskID=$taskID&browseType=assignedtome¶m=0"), $lang->testtask->assignedToMe) . ""; + ?> +
          +
          + id", $lang->testtask->linkCase); + echo html::a($this->session->testtaskList, $lang->goback); + ?> +
          +
          + + + + + + + +
          +
          +
          +
          +
          id");?>' target='hiddenwin'> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          idAB;?>priAB;?>testcase->title;?>testcase->type;?>testtask->assignedTo;?>testtask->lastRunAccount;?>testtask->lastRunTime;?>testtask->lastRunResult;?>statusAB;?>actions;?>
          case' /> "; printf('%03d', $run->case);?>pri?>createLink('testcase', 'view', "caseID=$run->case&version=$run->version"), $run->title, '_blank');?> + testcase->typeList[$run->type];?>assignedTo]; echo substr($assignedTo, strpos($assignedTo, ':') + 1);?>lastRunner]; echo substr($lastRunner, strpos($lastRunner, ':') + 1);?>lastRunDate)) echo date(DT_MONTHTIME1, strtotime($run->lastRunDate));?>lastRunResult) echo $lang->testcase->resultList[$run->lastRunResult];?>testtask->statusList[$run->status];?> + id", $lang->testtask->runCase, '', 'class="iframe"'); + common::printLink('testtask', 'results', "id=$run->id", $lang->testtask->results, '', 'class="iframe"'); + common::printLink('testtask', 'unlinkcase', "id=$run->id", $lang->testtask->unlinkCase, 'hiddenwin'); + if($run->lastRunResult == 'fail') common::printLink('bug', 'create', "product=$productID&extra=projectID=$task->project,buildID=$task->build,caseID=$run->case,runID=$run->id", $lang->testtask->createBug); + ?> +
          + + + + + +
          " . $lang->selectAll;?> + testtask->assign); + ?> +
          +
          +
          + diff --git a/module/testtask/view/create.html.php b/module/testtask/view/create.html.php index 2b9379976b..8fd2a1147b 100644 --- a/module/testtask/view/create.html.php +++ b/module/testtask/view/create.html.php @@ -1,67 +1,67 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testtask->create;?>
          testtask->product;?>
          testtask->project;?>
          testtask->build;?>
          testtask->owner;?>
          testtask->begin;?> -
          testtask->end;?> -
          testtask->status;?>testtask->statusList, '', "class='select-3'");?> -
          testtask->name;?> -
          testtask->desc;?> -
          -
          - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testtask->create;?>
          testtask->product;?>
          testtask->project;?>
          testtask->build;?>
          testtask->owner;?>
          testtask->begin;?> +
          testtask->end;?> +
          testtask->status;?>testtask->statusList, '', "class='select-3'");?> +
          testtask->name;?> +
          testtask->desc;?> +
          +
          + diff --git a/module/testtask/view/edit.html.php b/module/testtask/view/edit.html.php index 758919d3c6..6e268706ce 100644 --- a/module/testtask/view/edit.html.php +++ b/module/testtask/view/edit.html.php @@ -1,56 +1,56 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testtask->edit;?>
          testtask->project;?>project, 'class=select-3');?>
          testtask->build;?>build, 'class=select-3');?>
          testtask->owner;?>owner, 'class=select-3');?>
          testtask->begin;?>begin, "class='text-3 date'");?> -
          testtask->end;?>end, "class='text-3 date'");?> -
          testtask->status;?>testtask->statusList, $task->status, "class='select-3'");?> -
          testtask->name;?>name, "class='text-1'");?> -
          testtask->desc;?>desc), "rows=10 class='area-1'");?> -
          -
          - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testtask->edit;?>
          testtask->project;?>project, 'class=select-3');?>
          testtask->build;?>build, 'class=select-3');?>
          testtask->owner;?>owner, 'class=select-3');?>
          testtask->begin;?>begin, "class='text-3 date'");?> +
          testtask->end;?>end, "class='text-3 date'");?> +
          testtask->status;?>testtask->statusList, $task->status, "class='select-3'");?> +
          testtask->name;?>name, "class='text-1'");?> +
          testtask->desc;?>desc), "rows=10 class='area-1'");?> +
          +
          + diff --git a/module/testtask/view/linkcase.html.php b/module/testtask/view/linkcase.html.php index 765f6d8dbd..551fae6920 100644 --- a/module/testtask/view/linkcase.html.php +++ b/module/testtask/view/linkcase.html.php @@ -1,68 +1,68 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          -
          testtask->unlinkedCases;?>
          -
          session->testtaskList, $lang->goback);?>
          -
          createLink('testtask', 'linkcase', "taskID=$taskID¶m=bybug"), $lang->testtask->linkByBug);?>
          -
          createLink('testtask', 'linkcase', "taskID=$taskID¶m=bystory"), $lang->testtask->linkByStory);?>
          -
          idAB;?>priAB;?>testcase->title;?>testcase->type;?>openedByAB;?>statusAB;?>testtask->linkVersion;?>
          createLink('testcase', 'view', "testcaseID=$case->id"), sprintf('%03d', $case->id));?>pri?> - title . ' ( '; - for($i = $case->version; $i >= 1; $i --) - { - echo html::a($this->createLink('testcase', 'view', "caseID=$case->id&version=$i"), "#$i", '_blank'); - } - echo ')'; - ?> - testcase->typeList[$case->type];?>openedBy];?>testcase->statusList[$case->status];?> - - id]", array_combine(range($case->version, 1), range($case->version, 1)), '', 'style=width:50px');?> -
          show();?>
          selectAll; echo html::submitButton();?>
          -
          - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          testtask->unlinkedCases;?>
          +
          session->testtaskList, $lang->goback);?>
          +
          createLink('testtask', 'linkcase', "taskID=$taskID¶m=bybug"), $lang->testtask->linkByBug);?>
          +
          createLink('testtask', 'linkcase', "taskID=$taskID¶m=bystory"), $lang->testtask->linkByStory);?>
          +
          idAB;?>priAB;?>testcase->title;?>testcase->type;?>openedByAB;?>statusAB;?>testtask->linkVersion;?>
          createLink('testcase', 'view', "testcaseID=$case->id"), sprintf('%03d', $case->id));?>pri?> + title . ' ( '; + for($i = $case->version; $i >= 1; $i --) + { + echo html::a($this->createLink('testcase', 'view', "caseID=$case->id&version=$i"), "#$i", '_blank'); + } + echo ')'; + ?> + testcase->typeList[$case->type];?>openedBy];?>testcase->statusList[$case->status];?> + + id]", array_combine(range($case->version, 1), range($case->version, 1)), '', 'style=width:50px');?> +
          show();?>
          selectAll; echo html::submitButton();?>
          +
          + diff --git a/module/testtask/view/results.html.php b/module/testtask/view/results.html.php index a6f9c8693f..aef929a47c 100644 --- a/module/testtask/view/results.html.php +++ b/module/testtask/view/results.html.php @@ -1,49 +1,49 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -

          CASE#id. $lang->colon . $case->title;?>

          -
          - testcase->precondition;?> - precondition;?> -
          - - - - - - - - - - - stepResults as $key => $stepResult): - ?> - - - - - stepResults)):?> - - - - - - - - - -
          RESULT#id . ' ' . $result->date . ' ' . $users[$result->lastRunner] . ' ' . $lang->testtask->runCase . ':'. " " . $lang->testcase->resultList[$result->caseResult] . '';?>
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>testcase->result;?>testcase->real;?>
          a-center'>testcase->resultList[$stepResult['result']];?>
          - - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +

          CASE#id. $lang->colon . $case->title;?>

          +
          + testcase->precondition;?> + precondition;?> +
          + + + + + + + + + + + stepResults as $key => $stepResult): + ?> + + + + + stepResults)):?> + + + + + + + + + +
          RESULT#id . ' ' . $result->date . ' ' . $users[$result->lastRunner] . ' ' . $lang->testtask->runCase . ':'. " " . $lang->testcase->resultList[$result->caseResult] . '';?>
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>testcase->result;?>testcase->real;?>
          a-center'>testcase->resultList[$stepResult['result']];?>
          + + diff --git a/module/testtask/view/runcase.html.php b/module/testtask/view/runcase.html.php index c1840add67..f206738fd8 100644 --- a/module/testtask/view/runcase.html.php +++ b/module/testtask/view/runcase.html.php @@ -1,59 +1,59 @@ - - * @package testtask - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
          - - - - - - - - - - - - - case->steps as $key => $step):?> - expect ? 'pass' : 'n/a';?> - - - - - - - - - - - -
          CASE#case->id. $lang->colon . $run->case->title;?>
          testcase->precondition;?>
          case->precondition;?>
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>testcase->result;?>testcase->real;?>
          desc);?>expect);?>id]", $lang->testcase->resultList, $defaultResult);?>id]", '', "rows=3 class='area-1'");?>
          - case->steps)) - { - echo html::submitButton($lang->testtask->pass, "onclick=$('#result').val('pass')"); - echo html::submitButton($lang->testtask->fail, "onclick=$('#result').val('fail')"); - } - else - { - echo html::submitButton(); - echo html::submitButton($lang->testtask->passAll, "onclick=$('#passall').val(1)"); - } - echo html::hidden('case', $run->case->id); - echo html::hidden('version', $run->case->version); - if($run->case->steps) echo html::hidden('passall', 0); - if(!$run->case->steps) echo html::hidden('result', ''); - ?> -
          -
          - + + * @package testtask + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
          + + + + + + + + + + + + + case->steps as $key => $step):?> + expect ? 'pass' : 'n/a';?> + + + + + + + + + + + +
          CASE#case->id. $lang->colon . $run->case->title;?>
          testcase->precondition;?>
          case->precondition;?>
          testcase->stepID;?>testcase->stepDesc;?>testcase->stepExpect;?>testcase->result;?>testcase->real;?>
          desc);?>expect);?>id]", $lang->testcase->resultList, $defaultResult);?>id]", '', "rows=3 class='area-1'");?>
          + case->steps)) + { + echo html::submitButton($lang->testtask->pass, "onclick=$('#result').val('pass')"); + echo html::submitButton($lang->testtask->fail, "onclick=$('#result').val('fail')"); + } + else + { + echo html::submitButton(); + echo html::submitButton($lang->testtask->passAll, "onclick=$('#passall').val(1)"); + } + echo html::hidden('case', $run->case->id); + echo html::hidden('version', $run->case->version); + if($run->case->steps) echo html::hidden('passall', 0); + if(!$run->case->steps) echo html::hidden('result', ''); + ?> +
          +
          + diff --git a/module/testtask/view/view.html.php b/module/testtask/view/view.html.php index 223196e099..f61c14ed6a 100644 --- a/module/testtask/view/view.html.php +++ b/module/testtask/view/view.html.php @@ -1,64 +1,64 @@ - - * @package case - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          testtask->view;?>
          testtask->name;?>'>name;?> -
          testtask->project;?>projectName;?>
          testtask->build;?>buildName ? print($task->buildName) : print($task->build);?>
          testtask->owner;?>owner];?>
          testtask->begin;?>begin;?>
          testtask->end;?>end;?>
          testtask->status;?>testtask->statusList[$task->status];?>
          testtask->desc;?>desc;?>
          -
          - session->testtaskList ? $this->session->testtaskList : $this->createLink('testtask', 'browse', "productID=$task->product"); - if(!$task->deleted) - { - common::printLink('testtask', 'cases', "taskID=$task->id", $lang->testtask->cases); - common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); - common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); - common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - - + + * @package case + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          testtask->view;?>
          testtask->name;?>'>name;?> +
          testtask->project;?>projectName;?>
          testtask->build;?>buildName ? print($task->buildName) : print($task->build);?>
          testtask->owner;?>owner];?>
          testtask->begin;?>begin;?>
          testtask->end;?>end;?>
          testtask->status;?>testtask->statusList[$task->status];?>
          testtask->desc;?>desc;?>
          +
          + session->testtaskList ? $this->session->testtaskList : $this->createLink('testtask', 'browse', "productID=$task->product"); + if(!$task->deleted) + { + common::printLink('testtask', 'cases', "taskID=$task->id", $lang->testtask->cases); + common::printLink('testtask', 'linkcase', "taskID=$task->id", $lang->testtask->linkCaseAB); + common::printLink('testtask', 'edit', "taskID=$task->id", $lang->edit); + common::printLink('testtask', 'delete', "taskID=$task->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + + diff --git a/module/todo/control.php b/module/todo/control.php index a3d175f076..d590df5ac3 100644 --- a/module/todo/control.php +++ b/module/todo/control.php @@ -1,252 +1,252 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -class todo extends control -{ - /** - * Construct function, load model of task, bug, my. - * - * @access public - * @return voidzentaoms\www - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('task'); - $this->loadModel('bug'); - $this->loadModel('my')->setMenu(); - } - - /** - * Create a todo. - * - * @param string|date $date - * @param string $account - * @access public - * @return void - */ - public function create($date = 'today', $account = '') - { - if($date == 'today') $date = $this->todo->today(); - if($account == '') $account = $this->app->user->account; - if(!empty($_POST)) - { - $todoID = $this->todo->create($date, $account); - if(dao::isError()) die(js::error(dao::getError())); - $this->loadModel('action')->create('todo', $todoID, 'opened'); - die(js::locate($this->createLink('my', 'todo', "date=$_POST[date]"), 'parent')); - } - - $header['title'] = $this->lang->my->common . $this->lang->colon . $this->lang->todo->create; - $position[] = $this->lang->todo->create; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->dates = $this->todo->buildDateList(0, $this->config->todo->dates->end); - $this->view->date = $date; - $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); - $this->view->time = $this->todo->now(); - $this->display(); - } - - /** - * Edit a todo. - * - * @param int $todoID - * @access public - * @return void - */ - public function edit($todoID) - { - if(!empty($_POST)) - { - $changes = $this->todo->update($todoID); - if(dao::isError()) die(js::error(dao::getError())); - if($changes) - { - $actionID = $this->loadModel('action')->create('todo', $todoID, 'edited'); - $this->action->logHistory($actionID, $changes); - } - die(js::locate(inlink('view', "todoID=$todoID"), 'parent')); - } - - /* Judge a private todo or not, If private, die. */ - $todo = $this->todo->getById($todoID); - if($todo->private and $this->app->user->account != $todo->account) die('private'); - - $header['title'] = $this->lang->my->common . $this->lang->colon . $this->lang->todo->edit; - $position[] = $this->lang->todo->edit; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->dates = $this->todo->buildDateList(); - $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); - $this->view->todo = $todo; - $this->display(); - } - - /** - * View a todo. - * - * @param int $todoID - * @param string $from my|company - * @access public - * @return void - */ - public function view($todoID, $from = 'company') - { - $todo = $this->todo->getById($todoID); - if(!$todo) die(js::error($this->lang->notFound) . js::locate('back')); - - /* Save the session. */ - $this->session->set('taskList', $this->app->getURI(true)); - $this->session->set('bugList', $this->app->getURI(true)); - - /* Set menus. */ - $this->lang->todo->menu = $this->lang->user->menu; - $this->loadModel('user')->setMenu($this->user->getPairs(), $todo->account); - $this->lang->set('menugroup.todo', $from); - - $this->view->header->title = $this->lang->todo->view; - $this->view->position[] = $this->lang->todo->view; - $this->view->todo = $todo; - $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); - $this->view->users = $this->user->getPairs('noletter'); - $this->view->actions = $this->loadModel('action')->getList('todo', $todoID); - $this->view->from = $from; - - $this->display(); - } - - /** - * Delete a todo. - * - * @param int $todoID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($todoID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID=$todoID&confirm=yes")); - exit; - } - else - { - $this->dao->delete()->from(TABLE_TODO)->where('id')->eq($todoID)->exec(); - $this->loadModel('action')->create('todo', $todoID, 'erased'); - die(js::locate($this->session->todoList, 'parent')); - } - } - - /** - * Mark status of a todo. - * - * @param int $todoID - * @param string $status wait|doing|done - * @access public - * @return void - */ - public function mark($todoID, $status) - { - $this->todo->mark($todoID, $status); - $todo = $this->todo->getById($todoID); - if($todo->status == 'done') - { - if($todo->type == 'bug' or $todo->type == 'task') - { - $confirmNote = 'confirm' . ucfirst($todo->type); - $confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue"); - $cancelURL = $this->server->HTTP_REFERER; - die(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, 'parent', 'parent')); - } - } - die(js::reload('parent')); - } - - /** - * Import selected todoes to today. - * - * @access public - * @return void - */ - public function import2Today() - { - $todos = $this->post->todos; - $today = $this->todo->today(); - $this->dao->update(TABLE_TODO)->set('date')->eq($today)->where('id')->in($todos)->exec(); - die(js::reload('parent')); - } - - /** - * Get data to export - * - * @param string $productID - * @param string $orderBy - * @access public - * @return void - */ - public function export($account, $orderBy) - { - if($_POST) - { - $todoLang = $this->lang->todo; - $todoConfig = $this->config->todo; - - /* Create field lists. */ - $fields = explode(',', $todoConfig->list->exportFields); - foreach($fields as $key => $fieldName) - { - $fieldName = trim($fieldName); - $fields[$fieldName] = isset($todoLang->$fieldName) ? $todoLang->$fieldName : $fieldName; - unset($fields[$key]); - } - unset($fields['idvalue']); - unset($fields['private']); - - /* Get bugs. */ - $todos = $this->dao->select('*')->from(TABLE_TODO)->where($this->session->todoReportCondition)->orderBy($orderBy)->fetchAll('id'); - - /* Get users, bugs, tasks and times. */ - $users = $this->loadModel('user')->getPairs('noletter'); - $bugs = $this->loadModel('bug')->getUserBugPairs($account); - $tasks = $this->loadModel('task')->getUserTaskPairs($account); - $times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); - - foreach($todos as $todo) - { - /* fill some field with useful value. */ - if(isset($users[$todo->account])) $todo->account = $users[$todo->account]; - if(isset($times[$todo->begin])) $todo->begin = $times[$todo->begin]; - if(isset($times[$todo->end])) $todo->end = $times[$todo->end]; - if($todo->type == 'bug') $todo->name = isset($bugs[$todo->idvalue]) ? $bugs[$todo->idvalue] : ''; - if($todo->type == 'task') $todo->name = isset($tasks[$todo->idvalue]) ? $tasks[$todo->idvalue] : ''; - if(isset($todoLang->typeList->{$todo->type})) $todo->type = $todoLang->typeList->{$todo->type}; - if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri]; - if(isset($todoLang->statusList[$todo->status])) $todo->status = $todoLang->statusList[$todo->status]; - if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate; - - /* drop some field that is not needed. */ - unset($todo->company); - unset($todo->idvalue); - unset($todo->private); - } - - $this->post->set('fields', $fields); - $this->post->set('rows', $todos); - $this->fetch('file', 'export2' . $this->post->fileType, $_POST); - } - - $this->display(); - } -} + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +class todo extends control +{ + /** + * Construct function, load model of task, bug, my. + * + * @access public + * @return voidzentaoms\www + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('task'); + $this->loadModel('bug'); + $this->loadModel('my')->setMenu(); + } + + /** + * Create a todo. + * + * @param string|date $date + * @param string $account + * @access public + * @return void + */ + public function create($date = 'today', $account = '') + { + if($date == 'today') $date = $this->todo->today(); + if($account == '') $account = $this->app->user->account; + if(!empty($_POST)) + { + $todoID = $this->todo->create($date, $account); + if(dao::isError()) die(js::error(dao::getError())); + $this->loadModel('action')->create('todo', $todoID, 'opened'); + die(js::locate($this->createLink('my', 'todo', "date=$_POST[date]"), 'parent')); + } + + $header['title'] = $this->lang->my->common . $this->lang->colon . $this->lang->todo->create; + $position[] = $this->lang->todo->create; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->dates = $this->todo->buildDateList(0, $this->config->todo->dates->end); + $this->view->date = $date; + $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); + $this->view->time = $this->todo->now(); + $this->display(); + } + + /** + * Edit a todo. + * + * @param int $todoID + * @access public + * @return void + */ + public function edit($todoID) + { + if(!empty($_POST)) + { + $changes = $this->todo->update($todoID); + if(dao::isError()) die(js::error(dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('todo', $todoID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + die(js::locate(inlink('view', "todoID=$todoID"), 'parent')); + } + + /* Judge a private todo or not, If private, die. */ + $todo = $this->todo->getById($todoID); + if($todo->private and $this->app->user->account != $todo->account) die('private'); + + $header['title'] = $this->lang->my->common . $this->lang->colon . $this->lang->todo->edit; + $position[] = $this->lang->todo->edit; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->dates = $this->todo->buildDateList(); + $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); + $this->view->todo = $todo; + $this->display(); + } + + /** + * View a todo. + * + * @param int $todoID + * @param string $from my|company + * @access public + * @return void + */ + public function view($todoID, $from = 'company') + { + $todo = $this->todo->getById($todoID); + if(!$todo) die(js::error($this->lang->notFound) . js::locate('back')); + + /* Save the session. */ + $this->session->set('taskList', $this->app->getURI(true)); + $this->session->set('bugList', $this->app->getURI(true)); + + /* Set menus. */ + $this->lang->todo->menu = $this->lang->user->menu; + $this->loadModel('user')->setMenu($this->user->getPairs(), $todo->account); + $this->lang->set('menugroup.todo', $from); + + $this->view->header->title = $this->lang->todo->view; + $this->view->position[] = $this->lang->todo->view; + $this->view->todo = $todo; + $this->view->times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); + $this->view->users = $this->user->getPairs('noletter'); + $this->view->actions = $this->loadModel('action')->getList('todo', $todoID); + $this->view->from = $from; + + $this->display(); + } + + /** + * Delete a todo. + * + * @param int $todoID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($todoID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID=$todoID&confirm=yes")); + exit; + } + else + { + $this->dao->delete()->from(TABLE_TODO)->where('id')->eq($todoID)->exec(); + $this->loadModel('action')->create('todo', $todoID, 'erased'); + die(js::locate($this->session->todoList, 'parent')); + } + } + + /** + * Mark status of a todo. + * + * @param int $todoID + * @param string $status wait|doing|done + * @access public + * @return void + */ + public function mark($todoID, $status) + { + $this->todo->mark($todoID, $status); + $todo = $this->todo->getById($todoID); + if($todo->status == 'done') + { + if($todo->type == 'bug' or $todo->type == 'task') + { + $confirmNote = 'confirm' . ucfirst($todo->type); + $confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue"); + $cancelURL = $this->server->HTTP_REFERER; + die(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, 'parent', 'parent')); + } + } + die(js::reload('parent')); + } + + /** + * Import selected todoes to today. + * + * @access public + * @return void + */ + public function import2Today() + { + $todos = $this->post->todos; + $today = $this->todo->today(); + $this->dao->update(TABLE_TODO)->set('date')->eq($today)->where('id')->in($todos)->exec(); + die(js::reload('parent')); + } + + /** + * Get data to export + * + * @param string $productID + * @param string $orderBy + * @access public + * @return void + */ + public function export($account, $orderBy) + { + if($_POST) + { + $todoLang = $this->lang->todo; + $todoConfig = $this->config->todo; + + /* Create field lists. */ + $fields = explode(',', $todoConfig->list->exportFields); + foreach($fields as $key => $fieldName) + { + $fieldName = trim($fieldName); + $fields[$fieldName] = isset($todoLang->$fieldName) ? $todoLang->$fieldName : $fieldName; + unset($fields[$key]); + } + unset($fields['idvalue']); + unset($fields['private']); + + /* Get bugs. */ + $todos = $this->dao->select('*')->from(TABLE_TODO)->where($this->session->todoReportCondition)->orderBy($orderBy)->fetchAll('id'); + + /* Get users, bugs, tasks and times. */ + $users = $this->loadModel('user')->getPairs('noletter'); + $bugs = $this->loadModel('bug')->getUserBugPairs($account); + $tasks = $this->loadModel('task')->getUserTaskPairs($account); + $times = $this->todo->buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta); + + foreach($todos as $todo) + { + /* fill some field with useful value. */ + if(isset($users[$todo->account])) $todo->account = $users[$todo->account]; + if(isset($times[$todo->begin])) $todo->begin = $times[$todo->begin]; + if(isset($times[$todo->end])) $todo->end = $times[$todo->end]; + if($todo->type == 'bug') $todo->name = isset($bugs[$todo->idvalue]) ? $bugs[$todo->idvalue] : ''; + if($todo->type == 'task') $todo->name = isset($tasks[$todo->idvalue]) ? $tasks[$todo->idvalue] : ''; + if(isset($todoLang->typeList->{$todo->type})) $todo->type = $todoLang->typeList->{$todo->type}; + if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri]; + if(isset($todoLang->statusList[$todo->status])) $todo->status = $todoLang->statusList[$todo->status]; + if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate; + + /* drop some field that is not needed. */ + unset($todo->company); + unset($todo->idvalue); + unset($todo->private); + } + + $this->post->set('fields', $fields); + $this->post->set('rows', $todos); + $this->fetch('file', 'export2' . $this->post->fileType, $_POST); + } + + $this->display(); + } +} diff --git a/module/todo/lang/en.php b/module/todo/lang/en.php index 14d925744c..fcd9b6270f 100644 --- a/module/todo/lang/en.php +++ b/module/todo/lang/en.php @@ -1,78 +1,78 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->todo->common = 'TODO'; -$lang->todo->index = "Index"; -$lang->todo->create = "Create"; -$lang->todo->edit = "Edit"; -$lang->todo->view = "Info"; -$lang->todo->viewAB = "Info"; -$lang->todo->markDone = "Undone"; -$lang->todo->markWait = "Done"; -$lang->todo->markDoing = "Done"; -$lang->todo->mark = "Change status"; -$lang->todo->export = "Export"; -$lang->todo->delete = "Delete"; -$lang->todo->browse = "Browse"; -$lang->todo->import2Today = "Import to today"; -$lang->todo->changeStatus = "Change"; - -$lang->todo->id = 'ID'; -$lang->todo->account = 'Owner'; -$lang->todo->date = 'Date'; -$lang->todo->begin = 'Begin time'; -$lang->todo->beginAB = 'Begin'; -$lang->todo->end = 'End time'; -$lang->todo->endAB = 'End'; -$lang->todo->beginAndEnd = 'Begin and End'; -$lang->todo->type = 'Type'; -$lang->todo->pri = 'Priority'; -$lang->todo->name = 'Name'; -$lang->todo->status = 'Status'; -$lang->todo->desc = 'Desc'; -$lang->todo->private = 'Private'; -$lang->todo->idvalue = 'Task or bug'; - -$lang->todo->week = '(l)'; // date function's param. -$lang->todo->today = 'Today'; -$lang->todo->weekDateList = ''; -$lang->todo->dayInFuture = 'Future'; -$lang->todo->confirmBug = 'This todo linked to bug #%s,chang it also?'; -$lang->todo->confirmTask = 'This todo linked to task #%s,chang it also?'; - -$lang->todo->statusList['wait'] = 'Waiting'; -$lang->todo->statusList['doing'] = 'Doing'; -$lang->todo->statusList['done'] = 'Done'; -//$lang->todo->statusList['cancel'] = '已取消'; -//$lang->todo->statusList['postpone'] = '已延期'; - -$lang->todo->priList[3] = '3'; -$lang->todo->priList[1] = '1'; -$lang->todo->priList[2] = '2'; -$lang->todo->priList[4] = '4'; - -$lang->todo->typeList->custom = 'Custom'; -$lang->todo->typeList->bug = 'Bug'; -$lang->todo->typeList->task = 'Task'; - -$lang->todo->confirmDelete = "Are you sure to delete this todo?"; -$lang->todo->successMarked = "Successfully changed status";; -$lang->todo->thisIsPrivate = 'This is a private todo。:)'; -$lang->todo->lblDisableDate = 'Set time lately'; - -$lang->todo->thisWeekTodos = 'This week'; -$lang->todo->lastWeekTodos = 'Last week'; -$lang->todo->futureTodos = 'Future'; -$lang->todo->allDaysTodos = 'All todo'; -$lang->todo->allUndone = 'Undone'; -$lang->todo->todayTodos = 'Today'; - -$lang->todo->action->marked = array('main' => '$date, Change status to $extra by $actor。', 'extra' => $lang->todo->statusList); + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->todo->common = 'TODO'; +$lang->todo->index = "Index"; +$lang->todo->create = "Create"; +$lang->todo->edit = "Edit"; +$lang->todo->view = "Info"; +$lang->todo->viewAB = "Info"; +$lang->todo->markDone = "Undone"; +$lang->todo->markWait = "Done"; +$lang->todo->markDoing = "Done"; +$lang->todo->mark = "Change status"; +$lang->todo->export = "Export"; +$lang->todo->delete = "Delete"; +$lang->todo->browse = "Browse"; +$lang->todo->import2Today = "Import to today"; +$lang->todo->changeStatus = "Change"; + +$lang->todo->id = 'ID'; +$lang->todo->account = 'Owner'; +$lang->todo->date = 'Date'; +$lang->todo->begin = 'Begin time'; +$lang->todo->beginAB = 'Begin'; +$lang->todo->end = 'End time'; +$lang->todo->endAB = 'End'; +$lang->todo->beginAndEnd = 'Begin and End'; +$lang->todo->type = 'Type'; +$lang->todo->pri = 'Priority'; +$lang->todo->name = 'Name'; +$lang->todo->status = 'Status'; +$lang->todo->desc = 'Desc'; +$lang->todo->private = 'Private'; +$lang->todo->idvalue = 'Task or bug'; + +$lang->todo->week = '(l)'; // date function's param. +$lang->todo->today = 'Today'; +$lang->todo->weekDateList = ''; +$lang->todo->dayInFuture = 'Future'; +$lang->todo->confirmBug = 'This todo linked to bug #%s,chang it also?'; +$lang->todo->confirmTask = 'This todo linked to task #%s,chang it also?'; + +$lang->todo->statusList['wait'] = 'Waiting'; +$lang->todo->statusList['doing'] = 'Doing'; +$lang->todo->statusList['done'] = 'Done'; +//$lang->todo->statusList['cancel'] = '已取消'; +//$lang->todo->statusList['postpone'] = '已延期'; + +$lang->todo->priList[3] = '3'; +$lang->todo->priList[1] = '1'; +$lang->todo->priList[2] = '2'; +$lang->todo->priList[4] = '4'; + +$lang->todo->typeList->custom = 'Custom'; +$lang->todo->typeList->bug = 'Bug'; +$lang->todo->typeList->task = 'Task'; + +$lang->todo->confirmDelete = "Are you sure to delete this todo?"; +$lang->todo->successMarked = "Successfully changed status";; +$lang->todo->thisIsPrivate = 'This is a private todo。:)'; +$lang->todo->lblDisableDate = 'Set time lately'; + +$lang->todo->thisWeekTodos = 'This week'; +$lang->todo->lastWeekTodos = 'Last week'; +$lang->todo->futureTodos = 'Future'; +$lang->todo->allDaysTodos = 'All todo'; +$lang->todo->allUndone = 'Undone'; +$lang->todo->todayTodos = 'Today'; + +$lang->todo->action->marked = array('main' => '$date, Change status to $extra by $actor。', 'extra' => $lang->todo->statusList); diff --git a/module/todo/lang/zh-cn.php b/module/todo/lang/zh-cn.php index 9c784b23b9..4a4663c0cb 100644 --- a/module/todo/lang/zh-cn.php +++ b/module/todo/lang/zh-cn.php @@ -1,78 +1,78 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->todo->common = 'TODO'; -$lang->todo->index = "todo一览"; -$lang->todo->create = "新增TODO"; -$lang->todo->edit = "更新TODO"; -$lang->todo->view = "TODO详情"; -$lang->todo->viewAB = "详情"; -$lang->todo->markDone = "未完成"; -$lang->todo->markWait = "已完成"; -$lang->todo->markDoing = "已完成"; -$lang->todo->mark = "更改状态"; -$lang->todo->export = "导出"; -$lang->todo->delete = "删除TODO"; -$lang->todo->browse = "浏览TODO"; -$lang->todo->import2Today = "导入到今天"; -$lang->todo->changeStatus = "更改"; - -$lang->todo->id = '编号'; -$lang->todo->account = '所有者'; -$lang->todo->date = '日期'; -$lang->todo->begin = '开始时间'; -$lang->todo->beginAB = '开始'; -$lang->todo->end = '结束时间'; -$lang->todo->endAB = '结束'; -$lang->todo->beginAndEnd = '起止时间'; -$lang->todo->type = '类型'; -$lang->todo->pri = '优先级'; -$lang->todo->name = '名称'; -$lang->todo->status = '状态'; -$lang->todo->desc = '描述'; -$lang->todo->private = '私人事务'; -$lang->todo->idvalue = '任务或Bug'; - -$lang->todo->week = '星期'; -$lang->todo->today = '今天'; -$lang->todo->weekDateList = '一,二,三,四,五,六,天'; -$lang->todo->dayInFuture = '暂不指定'; -$lang->todo->confirmBug = '该Todo关联的是Bug #%s,需要修改它吗?'; -$lang->todo->confirmTask = '该Todo关联的是Task #%s,需要修改它吗?'; - -$lang->todo->statusList['wait'] = '未开始'; -$lang->todo->statusList['doing'] = '进行中'; -$lang->todo->statusList['done'] = '已完成'; -//$lang->todo->statusList['cancel'] = '已取消'; -//$lang->todo->statusList['postpone'] = '已延期'; - -$lang->todo->priList[3] = '一般'; -$lang->todo->priList[1] = '最高'; -$lang->todo->priList[2] = '较高'; -$lang->todo->priList[4] = '最低'; - -$lang->todo->typeList->custom = '自定义'; -$lang->todo->typeList->bug = 'Bug'; -$lang->todo->typeList->task = '项目任务'; - -$lang->todo->confirmDelete = "您确定要删除这个todo吗?"; -$lang->todo->successMarked = "成功切换状态!"; -$lang->todo->thisIsPrivate = '这是一条私人事务。:)'; -$lang->todo->lblDisableDate = '暂时不设定时间'; - -$lang->todo->thisWeekTodos = '本周计划'; -$lang->todo->lastWeekTodos = '上周总结'; -$lang->todo->futureTodos = '暂不指定'; -$lang->todo->allDaysTodos = '所有TODO'; -$lang->todo->allUndone = '之前未完'; -$lang->todo->todayTodos = '今日安排'; - -$lang->todo->action->marked = array('main' => '$date, 由 $actor 标记为$extra。', 'extra' => $lang->todo->statusList); + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->todo->common = 'TODO'; +$lang->todo->index = "todo一览"; +$lang->todo->create = "新增TODO"; +$lang->todo->edit = "更新TODO"; +$lang->todo->view = "TODO详情"; +$lang->todo->viewAB = "详情"; +$lang->todo->markDone = "未完成"; +$lang->todo->markWait = "已完成"; +$lang->todo->markDoing = "已完成"; +$lang->todo->mark = "更改状态"; +$lang->todo->export = "导出"; +$lang->todo->delete = "删除TODO"; +$lang->todo->browse = "浏览TODO"; +$lang->todo->import2Today = "导入到今天"; +$lang->todo->changeStatus = "更改"; + +$lang->todo->id = '编号'; +$lang->todo->account = '所有者'; +$lang->todo->date = '日期'; +$lang->todo->begin = '开始时间'; +$lang->todo->beginAB = '开始'; +$lang->todo->end = '结束时间'; +$lang->todo->endAB = '结束'; +$lang->todo->beginAndEnd = '起止时间'; +$lang->todo->type = '类型'; +$lang->todo->pri = '优先级'; +$lang->todo->name = '名称'; +$lang->todo->status = '状态'; +$lang->todo->desc = '描述'; +$lang->todo->private = '私人事务'; +$lang->todo->idvalue = '任务或Bug'; + +$lang->todo->week = '星期'; +$lang->todo->today = '今天'; +$lang->todo->weekDateList = '一,二,三,四,五,六,天'; +$lang->todo->dayInFuture = '暂不指定'; +$lang->todo->confirmBug = '该Todo关联的是Bug #%s,需要修改它吗?'; +$lang->todo->confirmTask = '该Todo关联的是Task #%s,需要修改它吗?'; + +$lang->todo->statusList['wait'] = '未开始'; +$lang->todo->statusList['doing'] = '进行中'; +$lang->todo->statusList['done'] = '已完成'; +//$lang->todo->statusList['cancel'] = '已取消'; +//$lang->todo->statusList['postpone'] = '已延期'; + +$lang->todo->priList[3] = '一般'; +$lang->todo->priList[1] = '最高'; +$lang->todo->priList[2] = '较高'; +$lang->todo->priList[4] = '最低'; + +$lang->todo->typeList->custom = '自定义'; +$lang->todo->typeList->bug = 'Bug'; +$lang->todo->typeList->task = '项目任务'; + +$lang->todo->confirmDelete = "您确定要删除这个todo吗?"; +$lang->todo->successMarked = "成功切换状态!"; +$lang->todo->thisIsPrivate = '这是一条私人事务。:)'; +$lang->todo->lblDisableDate = '暂时不设定时间'; + +$lang->todo->thisWeekTodos = '本周计划'; +$lang->todo->lastWeekTodos = '上周总结'; +$lang->todo->futureTodos = '暂不指定'; +$lang->todo->allDaysTodos = '所有TODO'; +$lang->todo->allUndone = '之前未完'; +$lang->todo->todayTodos = '今日安排'; + +$lang->todo->action->marked = array('main' => '$date, 由 $actor 标记为$extra。', 'extra' => $lang->todo->statusList); diff --git a/module/todo/lang/zh-tw.php b/module/todo/lang/zh-tw.php index 48bd2572f4..7342f55487 100644 --- a/module/todo/lang/zh-tw.php +++ b/module/todo/lang/zh-tw.php @@ -1,78 +1,78 @@ - - * @package todo - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->todo->common = 'TODO'; -$lang->todo->index = "todo一覽"; -$lang->todo->create = "新增TODO"; -$lang->todo->edit = "更新TODO"; -$lang->todo->view = "TODO詳情"; -$lang->todo->viewAB = "詳情"; -$lang->todo->markDone = "未完成"; -$lang->todo->markWait = "已完成"; -$lang->todo->markDoing = "已完成"; -$lang->todo->mark = "更改狀態"; -$lang->todo->export = "導出"; -$lang->todo->delete = "刪除TODO"; -$lang->todo->browse = "瀏覽TODO"; -$lang->todo->import2Today = "導入到今天"; -$lang->todo->changeStatus = "更改"; - -$lang->todo->id = '編號'; -$lang->todo->account = '所有者'; -$lang->todo->date = '日期'; -$lang->todo->begin = '開始時間'; -$lang->todo->beginAB = '開始'; -$lang->todo->end = '結束時間'; -$lang->todo->endAB = '結束'; -$lang->todo->beginAndEnd = '起止時間'; -$lang->todo->type = '類型'; -$lang->todo->pri = '優先順序'; -$lang->todo->name = '名稱'; -$lang->todo->status = '狀態'; -$lang->todo->desc = '描述'; -$lang->todo->private = '私人事務'; -$lang->todo->idvalue = '任務或Bug'; - -$lang->todo->week = '星期'; -$lang->todo->today = '今天'; -$lang->todo->weekDateList = '一,二,三,四,五,六,天'; -$lang->todo->dayInFuture = '暫不指定'; -$lang->todo->confirmBug = '該Todo關聯的是Bug #%s,需要修改它嗎?'; -$lang->todo->confirmTask = '該Todo關聯的是Task #%s,需要修改它嗎?'; - -$lang->todo->statusList['wait'] = '未開始'; -$lang->todo->statusList['doing'] = '進行中'; -$lang->todo->statusList['done'] = '已完成'; -//$lang->todo->statusList['cancel'] = '已取消'; -//$lang->todo->statusList['postpone'] = '已延期'; - -$lang->todo->priList[3] = '一般'; -$lang->todo->priList[1] = '最高'; -$lang->todo->priList[2] = '較高'; -$lang->todo->priList[4] = '最低'; - -$lang->todo->typeList->custom = '自定義'; -$lang->todo->typeList->bug = 'Bug'; -$lang->todo->typeList->task = '項目任務'; - -$lang->todo->confirmDelete = "您確定要刪除這個todo嗎?"; -$lang->todo->successMarked = "成功切換狀態!"; -$lang->todo->thisIsPrivate = '這是一條私人事務。:)'; -$lang->todo->lblDisableDate = '暫時不設定時間'; - -$lang->todo->thisWeekTodos = '本週計劃'; -$lang->todo->lastWeekTodos = '上周總結'; -$lang->todo->futureTodos = '暫不指定'; -$lang->todo->allDaysTodos = '所有TODO'; -$lang->todo->allUndone = '之前未完'; -$lang->todo->todayTodos = '今日安排'; - -$lang->todo->action->marked = array('main' => '$date, 由 $actor 標記為$extra。', 'extra' => $lang->todo->statusList); + + * @package todo + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->todo->common = 'TODO'; +$lang->todo->index = "todo一覽"; +$lang->todo->create = "新增TODO"; +$lang->todo->edit = "更新TODO"; +$lang->todo->view = "TODO詳情"; +$lang->todo->viewAB = "詳情"; +$lang->todo->markDone = "未完成"; +$lang->todo->markWait = "已完成"; +$lang->todo->markDoing = "已完成"; +$lang->todo->mark = "更改狀態"; +$lang->todo->export = "導出"; +$lang->todo->delete = "刪除TODO"; +$lang->todo->browse = "瀏覽TODO"; +$lang->todo->import2Today = "導入到今天"; +$lang->todo->changeStatus = "更改"; + +$lang->todo->id = '編號'; +$lang->todo->account = '所有者'; +$lang->todo->date = '日期'; +$lang->todo->begin = '開始時間'; +$lang->todo->beginAB = '開始'; +$lang->todo->end = '結束時間'; +$lang->todo->endAB = '結束'; +$lang->todo->beginAndEnd = '起止時間'; +$lang->todo->type = '類型'; +$lang->todo->pri = '優先順序'; +$lang->todo->name = '名稱'; +$lang->todo->status = '狀態'; +$lang->todo->desc = '描述'; +$lang->todo->private = '私人事務'; +$lang->todo->idvalue = '任務或Bug'; + +$lang->todo->week = '星期'; +$lang->todo->today = '今天'; +$lang->todo->weekDateList = '一,二,三,四,五,六,天'; +$lang->todo->dayInFuture = '暫不指定'; +$lang->todo->confirmBug = '該Todo關聯的是Bug #%s,需要修改它嗎?'; +$lang->todo->confirmTask = '該Todo關聯的是Task #%s,需要修改它嗎?'; + +$lang->todo->statusList['wait'] = '未開始'; +$lang->todo->statusList['doing'] = '進行中'; +$lang->todo->statusList['done'] = '已完成'; +//$lang->todo->statusList['cancel'] = '已取消'; +//$lang->todo->statusList['postpone'] = '已延期'; + +$lang->todo->priList[3] = '一般'; +$lang->todo->priList[1] = '最高'; +$lang->todo->priList[2] = '較高'; +$lang->todo->priList[4] = '最低'; + +$lang->todo->typeList->custom = '自定義'; +$lang->todo->typeList->bug = 'Bug'; +$lang->todo->typeList->task = '項目任務'; + +$lang->todo->confirmDelete = "您確定要刪除這個todo嗎?"; +$lang->todo->successMarked = "成功切換狀態!"; +$lang->todo->thisIsPrivate = '這是一條私人事務。:)'; +$lang->todo->lblDisableDate = '暫時不設定時間'; + +$lang->todo->thisWeekTodos = '本週計劃'; +$lang->todo->lastWeekTodos = '上周總結'; +$lang->todo->futureTodos = '暫不指定'; +$lang->todo->allDaysTodos = '所有TODO'; +$lang->todo->allUndone = '之前未完'; +$lang->todo->todayTodos = '今日安排'; + +$lang->todo->action->marked = array('main' => '$date, 由 $actor 標記為$extra。', 'extra' => $lang->todo->statusList); diff --git a/module/todo/model.php b/module/todo/model.php index 2ca5df9dc5..44635c7bda 100644 --- a/module/todo/model.php +++ b/module/todo/model.php @@ -1,428 +1,428 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -?> -add('account', $this->app->user->account) - ->add('idvalue', 0) - ->specialChars('type,name') - ->cleanInt('date, pri, begin, end, private') - ->setIF($this->post->type != 'custom', 'name', '') - ->setIF($this->post->type == 'bug' and $this->post->bug, 'idvalue', $this->post->bug) - ->setIF($this->post->type == 'task' and $this->post->task, 'idvalue', $this->post->task) - ->setIF($this->post->begin == false, 'begin', '2400') - ->setIF($this->post->end == false, 'end', '2400') - ->remove('bug, task') - ->get(); - - $this->dao->insert(TABLE_TODO)->data($todo) - ->autoCheck() - ->checkIF($todo->type == 'custom', $this->config->todo->create->requiredFields, 'notempty') - ->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty') - ->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty') - ->exec(); - return $this->dao->lastInsertID(); - } - - /** - * update a todo. - * - * @param int $todoID - * @access public - * @return void - */ - public function update($todoID) - { - $oldTodo = $this->getById($todoID); - if($oldTodo->type != 'custom') $oldTodo->name = ''; - $todo = fixer::input('post') - ->cleanInt('date, pri, begin, end, private') - ->specialChars('type,name') - ->setIF($this->post->type != 'custom', 'name', '') - ->setIF($this->post->begin == false, 'begin', '2400') - ->setIF($this->post->end == false, 'end', '2400') - ->setDefault('private', 0) - ->get(); - $this->dao->update(TABLE_TODO)->data($todo) - ->autoCheck() - ->checkIF($todo->type == 'custom', $this->config->todo->edit->requiredFields, 'notempty')->where('id')->eq($todoID) - ->exec(); - if(!dao::isError()) return common::createChanges($oldTodo, $todo); - } - - /** - * Change the status of a todo. - * - * @param string $todoID - * @param string $status - * @access public - * @return void - */ - public function mark($todoID, $status) - { - $status = ($status == 'done') ? 'wait' : 'done'; - $this->dao->update(TABLE_TODO)->set('status')->eq($status)->where('id')->eq((int)$todoID)->exec(); - $this->loadModel('action')->create('todo', $todoID, 'marked', '', $status); - return; - } - - /** - * Get info of a todo. - * - * @param int $todoID - * @access public - * @return object|bool - */ - public function getById($todoID) - { - $todo = $this->dao->findById((int)$todoID)->from(TABLE_TODO)->fetch(); - if(!$todo) return false; - $todo->desc = $this->loadModel('file')->setImgSize($todo->desc); - if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name'); - if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title'); - $todo->date = str_replace('-', '', $todo->date); - return $todo; - } - - /** - * Get todo list of a user. - * - * @param date $date - * @param string $account - * @param string $status all|today|thisweek|lastweek|before, or a date. - * @param int $limit - * @access public - * @return void - */ - public function getList($date = 'today', $account = '', $status = 'all', $limit = 0) - { - $todos = array(); - if($date == 'today') - { - $begin = $this->today(); - $end = $begin; - } - elseif($date == 'thisweek') - { - extract($this->getThisWeek()); - } - elseif($date == 'lastweek') - { - extract($this->getLastWeek()); - } - elseif($date == 'future') - { - $begin = '2030-01-01'; - $end = $begin; - } - elseif($date == 'all') - { - $begin = '1970-01-01'; - $end = '2109-01-01'; - } - elseif($date == 'before') - { - $begin = '1970-01-01'; - $end = $this->yesterday(); - } - else - { - $begin = $end = $date; - } - - if($account == '') $account = $this->app->user->account; - - $stmt = $this->dao->select('*')->from(TABLE_TODO) - ->where('account')->eq($account) - ->andWhere("date >= '$begin'") - ->andWhere("date <= '$end'") - ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() - ->beginIF($status == 'undone')->andWhere('status')->ne('done')->fi() - ->orderBy('date, status, begin') - ->beginIF($limit > 0)->limit($limit)->fi() - ->query(); - - /* Set session. */ - $sql = explode('WHERE', $this->dao->get()); - $sql = explode('ORDER', $sql[1]); - $this->session->set('todoReportCondition', $sql[0]); - - while($todo = $stmt->fetch()) - { - if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name'); - if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title'); - $todo->begin = $this->formatTime($todo->begin); - $todo->end = $this->formatTime($todo->end); - - /* If is private, change the title to private. */ - if($todo->private and $this->app->user->account != $todo->account) $todo->name = $this->lang->todo->thisIsPrivate; - $todos[] = $todo; - } - return $todos; - } - - /** - * Build date list, for selection use. - * - * @param int $before - * @param int $after - * @access public - * @return void - */ - public function buildDateList($before = 7, $after = 7) - { - $today = strtotime($this->today()); - $delta = 60 * 60 * 24; - $dates = array(); - $weekList = range(1, 7); - $weekDateList = explode(',', $this->lang->todo->weekDateList); - for($i = -1 * $before; $i <= $after; $i ++) - { - $time = $today + $i * $delta; - $label = date(DT_DATE1, $time); - if($i == 0) - { - $label .= " ({$this->lang->todo->today})"; - } - else - { - if($this->cookie->lang == 'zh-cn' or $this->cookie->lang == 'zh-tw') - { - $label .= str_replace($weekList, $weekDateList, date(" ({$this->lang->todo->week}N)", $time)); - } - else - { - $label .= date($this->lang->todo->week, $time); - } - } - $date = date(DT_DATE2, $time); - $dates[$date] = $label; - } - $dates[self::DAY_IN_FUTURE] = $this->lang->todo->dayInFuture; - return $dates; - } - - /** - * Build hour time list. - * - * @param int $begin - * @param int $end - * @param int $delta - * @access public - * @return array - */ - public function buildTimeList($begin, $end, $delta) - { - $times = array(); - for($hour = $begin; $hour <= $end; $hour ++) - { - for($minutes = 0; $minutes < 60; $minutes += $delta) - { - $time = sprintf('%02d%02d', $hour, $minutes); - $label = sprintf('%02d:%02d', $hour, $minutes); - $times[$time] = $label; - } - } - return $times; - } - - /** - * Get today. - * - * @access public - * @return date - */ - public function today() - { - return date(DT_DATE2, time()); - } - - /** - * Get yesterday - * - * @access public - * @return date - */ - public function yesterday() - { - return date(DT_DATE1, strtotime('yesterday')); - } - - /** - * Get tomorrow. - * - * @access public - * @return date - */ - public function tomorrow() - { - return date(DT_DATE1, strtotime('tomorrow')); - } - - /** - * Get the day before yesterday. - * - * @access public - * @return date - */ - public function twoDaysAgo() - { - return date(DT_DATE1, strtotime('-2 days')); - } - - /** - * Get now time period. - * - * @param int $delta - * @access public - * @return string the current time period, like 0915 - */ - public function now($delta = 10) - { - $range = range($delta, 60 - $delta, $delta); - $hour = date('H', time()); - $minute = date('i', time()); - - if($minute > 60 - $delta) - { - $hour += 1; - $minute = 00; - } - else - { - for($i = 0; $i < $delta; $i ++) - { - if(in_array($minute + $i, $range)) - { - $minute = $minute + $i; - break; - } - } - } - - return sprintf('%02d%02d', $hour, $minute); - } - - /** - * Format time 0915 to 09:15 - * - * @param string $time - * @access public - * @return string - */ - public function formatTime($time) - { - if(strlen($time) != 4 or $time == '2400') return ''; - return substr($time, 0, 2) . ':' . substr($time, 2, 2); - } - - /** - * Get the begin and end date of this week. - * - * @access public - * @return array - */ - public function getThisWeek() - { - $baseTime = $this->getMiddleOfThisWeek(); - $begin = date(DT_DATE1, strtotime('last monday', $baseTime)); - $end = date(DT_DATE1, strtotime('next sunday', $baseTime)); - return array('begin' => $begin, 'end' => $end); - } - - /** - * Get the begin and end date of last week. - * - * @access public - * @return array - */ - public function getLastWeek() - { - $baseTime = $this->getMiddleOfLastWeek(); - $begin = date(DT_DATE1, strtotime('last monday', $baseTime)); - $end = date(DT_DATE1, strtotime('next sunday', $baseTime)); - return array('begin' => $begin, 'end' => $end); - } - - /** - * Get the time at the middle of this week. - * - * If today in week is 1, move it one day in future. Else is 7, move it back one day. To keep the time geted in this week. - * - * @access public - * @return time - */ - public function getMiddleOfThisWeek() - { - $baseTime = time(); - $weekDay = date('N'); - if($weekDay == 1) $baseTime = time() + 86400; - if($weekDay == 7) $baseTime = time() - 86400; - return $baseTime; - } - - /** - * Get middle of last week - * - * @access public - * @return time - */ - public function getMiddleOfLastWeek() - { - $baseTime = time(); - $weekDay = date('N'); - $baseTime = time() - 86400 * 7; - if($weekDay == 1) $baseTime = time() - 86400 * 4; // Make sure is last thursday. - if($weekDay == 7) $baseTime = time() - 86400 * 10; // Make sure is last thursday. - return $baseTime; - } - - /** - * Get this month begin and end time - * - * @access public - * @return array - */ - public function getThisMonth() - { - $begin = date('Y-m'); - $end = date('Y-m', strtotime('next month')); - return array('begin' => $begin, 'end' => $end); - } - - /** - * Get last month begin and end time - * - * @access public - * @return array - */ - public function getLastMonth() - { - $begin = date('Y-m', strtotime('last month')); - $end = date('Y-m', strtotime('this month')); - return array('begin' => $begin, 'end' => $end); - } -} + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +?> +add('account', $this->app->user->account) + ->add('idvalue', 0) + ->specialChars('type,name') + ->cleanInt('date, pri, begin, end, private') + ->setIF($this->post->type != 'custom', 'name', '') + ->setIF($this->post->type == 'bug' and $this->post->bug, 'idvalue', $this->post->bug) + ->setIF($this->post->type == 'task' and $this->post->task, 'idvalue', $this->post->task) + ->setIF($this->post->begin == false, 'begin', '2400') + ->setIF($this->post->end == false, 'end', '2400') + ->remove('bug, task') + ->get(); + + $this->dao->insert(TABLE_TODO)->data($todo) + ->autoCheck() + ->checkIF($todo->type == 'custom', $this->config->todo->create->requiredFields, 'notempty') + ->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty') + ->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty') + ->exec(); + return $this->dao->lastInsertID(); + } + + /** + * update a todo. + * + * @param int $todoID + * @access public + * @return void + */ + public function update($todoID) + { + $oldTodo = $this->getById($todoID); + if($oldTodo->type != 'custom') $oldTodo->name = ''; + $todo = fixer::input('post') + ->cleanInt('date, pri, begin, end, private') + ->specialChars('type,name') + ->setIF($this->post->type != 'custom', 'name', '') + ->setIF($this->post->begin == false, 'begin', '2400') + ->setIF($this->post->end == false, 'end', '2400') + ->setDefault('private', 0) + ->get(); + $this->dao->update(TABLE_TODO)->data($todo) + ->autoCheck() + ->checkIF($todo->type == 'custom', $this->config->todo->edit->requiredFields, 'notempty')->where('id')->eq($todoID) + ->exec(); + if(!dao::isError()) return common::createChanges($oldTodo, $todo); + } + + /** + * Change the status of a todo. + * + * @param string $todoID + * @param string $status + * @access public + * @return void + */ + public function mark($todoID, $status) + { + $status = ($status == 'done') ? 'wait' : 'done'; + $this->dao->update(TABLE_TODO)->set('status')->eq($status)->where('id')->eq((int)$todoID)->exec(); + $this->loadModel('action')->create('todo', $todoID, 'marked', '', $status); + return; + } + + /** + * Get info of a todo. + * + * @param int $todoID + * @access public + * @return object|bool + */ + public function getById($todoID) + { + $todo = $this->dao->findById((int)$todoID)->from(TABLE_TODO)->fetch(); + if(!$todo) return false; + $todo->desc = $this->loadModel('file')->setImgSize($todo->desc); + if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name'); + if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title'); + $todo->date = str_replace('-', '', $todo->date); + return $todo; + } + + /** + * Get todo list of a user. + * + * @param date $date + * @param string $account + * @param string $status all|today|thisweek|lastweek|before, or a date. + * @param int $limit + * @access public + * @return void + */ + public function getList($date = 'today', $account = '', $status = 'all', $limit = 0) + { + $todos = array(); + if($date == 'today') + { + $begin = $this->today(); + $end = $begin; + } + elseif($date == 'thisweek') + { + extract($this->getThisWeek()); + } + elseif($date == 'lastweek') + { + extract($this->getLastWeek()); + } + elseif($date == 'future') + { + $begin = '2030-01-01'; + $end = $begin; + } + elseif($date == 'all') + { + $begin = '1970-01-01'; + $end = '2109-01-01'; + } + elseif($date == 'before') + { + $begin = '1970-01-01'; + $end = $this->yesterday(); + } + else + { + $begin = $end = $date; + } + + if($account == '') $account = $this->app->user->account; + + $stmt = $this->dao->select('*')->from(TABLE_TODO) + ->where('account')->eq($account) + ->andWhere("date >= '$begin'") + ->andWhere("date <= '$end'") + ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi() + ->beginIF($status == 'undone')->andWhere('status')->ne('done')->fi() + ->orderBy('date, status, begin') + ->beginIF($limit > 0)->limit($limit)->fi() + ->query(); + + /* Set session. */ + $sql = explode('WHERE', $this->dao->get()); + $sql = explode('ORDER', $sql[1]); + $this->session->set('todoReportCondition', $sql[0]); + + while($todo = $stmt->fetch()) + { + if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name'); + if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title'); + $todo->begin = $this->formatTime($todo->begin); + $todo->end = $this->formatTime($todo->end); + + /* If is private, change the title to private. */ + if($todo->private and $this->app->user->account != $todo->account) $todo->name = $this->lang->todo->thisIsPrivate; + $todos[] = $todo; + } + return $todos; + } + + /** + * Build date list, for selection use. + * + * @param int $before + * @param int $after + * @access public + * @return void + */ + public function buildDateList($before = 7, $after = 7) + { + $today = strtotime($this->today()); + $delta = 60 * 60 * 24; + $dates = array(); + $weekList = range(1, 7); + $weekDateList = explode(',', $this->lang->todo->weekDateList); + for($i = -1 * $before; $i <= $after; $i ++) + { + $time = $today + $i * $delta; + $label = date(DT_DATE1, $time); + if($i == 0) + { + $label .= " ({$this->lang->todo->today})"; + } + else + { + if($this->cookie->lang == 'zh-cn' or $this->cookie->lang == 'zh-tw') + { + $label .= str_replace($weekList, $weekDateList, date(" ({$this->lang->todo->week}N)", $time)); + } + else + { + $label .= date($this->lang->todo->week, $time); + } + } + $date = date(DT_DATE2, $time); + $dates[$date] = $label; + } + $dates[self::DAY_IN_FUTURE] = $this->lang->todo->dayInFuture; + return $dates; + } + + /** + * Build hour time list. + * + * @param int $begin + * @param int $end + * @param int $delta + * @access public + * @return array + */ + public function buildTimeList($begin, $end, $delta) + { + $times = array(); + for($hour = $begin; $hour <= $end; $hour ++) + { + for($minutes = 0; $minutes < 60; $minutes += $delta) + { + $time = sprintf('%02d%02d', $hour, $minutes); + $label = sprintf('%02d:%02d', $hour, $minutes); + $times[$time] = $label; + } + } + return $times; + } + + /** + * Get today. + * + * @access public + * @return date + */ + public function today() + { + return date(DT_DATE2, time()); + } + + /** + * Get yesterday + * + * @access public + * @return date + */ + public function yesterday() + { + return date(DT_DATE1, strtotime('yesterday')); + } + + /** + * Get tomorrow. + * + * @access public + * @return date + */ + public function tomorrow() + { + return date(DT_DATE1, strtotime('tomorrow')); + } + + /** + * Get the day before yesterday. + * + * @access public + * @return date + */ + public function twoDaysAgo() + { + return date(DT_DATE1, strtotime('-2 days')); + } + + /** + * Get now time period. + * + * @param int $delta + * @access public + * @return string the current time period, like 0915 + */ + public function now($delta = 10) + { + $range = range($delta, 60 - $delta, $delta); + $hour = date('H', time()); + $minute = date('i', time()); + + if($minute > 60 - $delta) + { + $hour += 1; + $minute = 00; + } + else + { + for($i = 0; $i < $delta; $i ++) + { + if(in_array($minute + $i, $range)) + { + $minute = $minute + $i; + break; + } + } + } + + return sprintf('%02d%02d', $hour, $minute); + } + + /** + * Format time 0915 to 09:15 + * + * @param string $time + * @access public + * @return string + */ + public function formatTime($time) + { + if(strlen($time) != 4 or $time == '2400') return ''; + return substr($time, 0, 2) . ':' . substr($time, 2, 2); + } + + /** + * Get the begin and end date of this week. + * + * @access public + * @return array + */ + public function getThisWeek() + { + $baseTime = $this->getMiddleOfThisWeek(); + $begin = date(DT_DATE1, strtotime('last monday', $baseTime)); + $end = date(DT_DATE1, strtotime('next sunday', $baseTime)); + return array('begin' => $begin, 'end' => $end); + } + + /** + * Get the begin and end date of last week. + * + * @access public + * @return array + */ + public function getLastWeek() + { + $baseTime = $this->getMiddleOfLastWeek(); + $begin = date(DT_DATE1, strtotime('last monday', $baseTime)); + $end = date(DT_DATE1, strtotime('next sunday', $baseTime)); + return array('begin' => $begin, 'end' => $end); + } + + /** + * Get the time at the middle of this week. + * + * If today in week is 1, move it one day in future. Else is 7, move it back one day. To keep the time geted in this week. + * + * @access public + * @return time + */ + public function getMiddleOfThisWeek() + { + $baseTime = time(); + $weekDay = date('N'); + if($weekDay == 1) $baseTime = time() + 86400; + if($weekDay == 7) $baseTime = time() - 86400; + return $baseTime; + } + + /** + * Get middle of last week + * + * @access public + * @return time + */ + public function getMiddleOfLastWeek() + { + $baseTime = time(); + $weekDay = date('N'); + $baseTime = time() - 86400 * 7; + if($weekDay == 1) $baseTime = time() - 86400 * 4; // Make sure is last thursday. + if($weekDay == 7) $baseTime = time() - 86400 * 10; // Make sure is last thursday. + return $baseTime; + } + + /** + * Get this month begin and end time + * + * @access public + * @return array + */ + public function getThisMonth() + { + $begin = date('Y-m'); + $end = date('Y-m', strtotime('next month')); + return array('begin' => $begin, 'end' => $end); + } + + /** + * Get last month begin and end time + * + * @access public + * @return array + */ + public function getLastMonth() + { + $begin = date('Y-m', strtotime('last month')); + $end = date('Y-m', strtotime('this month')); + return array('begin' => $begin, 'end' => $end); + } +} diff --git a/module/todo/view/create.html.php b/module/todo/view/create.html.php index da82852244..2da4de5cf8 100644 --- a/module/todo/view/create.html.php +++ b/module/todo/view/create.html.php @@ -1,61 +1,61 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          todo->create;?>
          todo->date;?>
          todo->type;?>todo->typeList, '', 'onchange=loadList(this.value); class=select-3');?> -
          todo->pri;?>todo->priList, '', 'class=select-3');?>
          todo->name;?>
          todo->desc;?> -
          todo->status;?>todo->statusList, '', 'class=select-3');?>
          todo->beginAndEnd;?> - - todo->lblDisableDate;?> -
          todo->private;?>
          - -
          -
          - - + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          todo->create;?>
          todo->date;?>
          todo->type;?>todo->typeList, '', 'onchange=loadList(this.value); class=select-3');?> +
          todo->pri;?>todo->priList, '', 'class=select-3');?>
          todo->name;?>
          todo->desc;?> +
          todo->status;?>todo->statusList, '', 'class=select-3');?>
          todo->beginAndEnd;?> + + todo->lblDisableDate;?> +
          todo->private;?>
          + +
          +
          + + diff --git a/module/todo/view/edit.html.php b/module/todo/view/edit.html.php index 1476feafd2..8e3257bbf7 100644 --- a/module/todo/view/edit.html.php +++ b/module/todo/view/edit.html.php @@ -1,67 +1,67 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          todo->edit;?>
          todo->date;?>date, 'class=select-3');?>
          todo->type;?>todo->typeList->{$todo->type};?>
          todo->pri;?>todo->priList, $todo->pri, 'class=select-3');?>
          todo->name;?>
          - type != 'custom' ? 'readonly' : ''; - echo html::input('name', $todo->name, "$readType class=text-1"); - ?> -
          -
          todo->desc;?>desc), "rows=8 class=area-1");?>
          todo->status;?>todo->statusList, $todo->status, 'class=select-3');?>
          todo->beginAndEnd;?> - begin, 'onchange=selectNext(); class=select-2') . html::select('end', $times, $todo->end, 'class=select-2');?> - begin == 2400) echo 'checked';?> >todo->lblDisableDate;?> -
          todo->private;?>private) echo 'checked';?>>
          - -
          -
          - - + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          todo->edit;?>
          todo->date;?>date, 'class=select-3');?>
          todo->type;?>todo->typeList->{$todo->type};?>
          todo->pri;?>todo->priList, $todo->pri, 'class=select-3');?>
          todo->name;?>
          + type != 'custom' ? 'readonly' : ''; + echo html::input('name', $todo->name, "$readType class=text-1"); + ?> +
          +
          todo->desc;?>desc), "rows=8 class=area-1");?>
          todo->status;?>todo->statusList, $todo->status, 'class=select-3');?>
          todo->beginAndEnd;?> + begin, 'onchange=selectNext(); class=select-2') . html::select('end', $times, $todo->end, 'class=select-2');?> + begin == 2400) echo 'checked';?> >todo->lblDisableDate;?> +
          todo->private;?>private) echo 'checked';?>>
          + +
          +
          + + diff --git a/module/todo/view/export.html.php b/module/todo/view/export.html.php index 5bc94f06fc..6bc1e78954 100755 --- a/module/todo/view/export.html.php +++ b/module/todo/view/export.html.php @@ -1,13 +1,13 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -?> - + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +?> + diff --git a/module/todo/view/view.html.php b/module/todo/view/view.html.php index 20e0f7c38e..004f472b36 100644 --- a/module/todo/view/view.html.php +++ b/module/todo/view/view.html.php @@ -1,87 +1,87 @@ - - * @package todo - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -private or ($todo->private and $todo->account == $app->user->account)):?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          todo->view;?>
          todo->account;?>account;?>
          todo->date;?>date == TODOModel::DAY_IN_FUTURE ? $lang->todo->dayInFuture : date(DT_DATE1, strtotime($todo->date)));?>
          todo->type;?>todo->typeList->{$todo->type};?>
          todo->pri;?>todo->priList[$todo->pri];?>
          todo->name;?> - type == 'bug') echo html::a($this->createLink('bug', 'view', "id={$todo->idvalue}"), $todo->name); - if($todo->type == 'task') echo html::a($this->createLink('task', 'view', "id={$todo->idvalue}"), $todo->name); - if($todo->type == 'custom') echo $todo->name; - ?> -
          todo->desc;?>desc;?>
          todo->status;?>todo->statusList[$todo->status];?>
          todo->beginAndEnd;?> - begin])) echo $times[$todo->begin]; - if(isset($times[$todo->end])) echo ' ~ ' . $times[$todo->end]; - ?> -
          -
          - session->todoList) - { - $browseLink = $this->session->todoList; - } - elseif($todo->account == $app->user->account) - { - $browseLink = $this->createLink('my', 'todo'); - } - else - { - $browseLink = $this->createLink('user', 'todo', "account=$todo->account"); - } - if($todo->account == $app->user->account) - { - common::printLink('todo', 'edit', "todoID=$todo->id", $lang->edit); - common::printLink('todo', 'delete', "todoID=$todo->id", $lang->delete, 'hiddenwin'); - } - echo html::a($browseLink, $lang->goback); - ?> -
          - - -todo->thisIsPrivate;?> - - + + * @package todo + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +private or ($todo->private and $todo->account == $app->user->account)):?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          todo->view;?>
          todo->account;?>account;?>
          todo->date;?>date == TODOModel::DAY_IN_FUTURE ? $lang->todo->dayInFuture : date(DT_DATE1, strtotime($todo->date)));?>
          todo->type;?>todo->typeList->{$todo->type};?>
          todo->pri;?>todo->priList[$todo->pri];?>
          todo->name;?> + type == 'bug') echo html::a($this->createLink('bug', 'view', "id={$todo->idvalue}"), $todo->name); + if($todo->type == 'task') echo html::a($this->createLink('task', 'view', "id={$todo->idvalue}"), $todo->name); + if($todo->type == 'custom') echo $todo->name; + ?> +
          todo->desc;?>desc;?>
          todo->status;?>todo->statusList[$todo->status];?>
          todo->beginAndEnd;?> + begin])) echo $times[$todo->begin]; + if(isset($times[$todo->end])) echo ' ~ ' . $times[$todo->end]; + ?> +
          +
          + session->todoList) + { + $browseLink = $this->session->todoList; + } + elseif($todo->account == $app->user->account) + { + $browseLink = $this->createLink('my', 'todo'); + } + else + { + $browseLink = $this->createLink('user', 'todo', "account=$todo->account"); + } + if($todo->account == $app->user->account) + { + common::printLink('todo', 'edit', "todoID=$todo->id", $lang->edit); + common::printLink('todo', 'delete', "todoID=$todo->id", $lang->delete, 'hiddenwin'); + } + echo html::a($browseLink, $lang->goback); + ?> +
          + + +todo->thisIsPrivate;?> + + diff --git a/module/tree/control.php b/module/tree/control.php index 8db150cc6e..f0d2c77524 100644 --- a/module/tree/control.php +++ b/module/tree/control.php @@ -1,237 +1,237 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -class tree extends control -{ - const NEW_CHILD_COUNT = 5; - - /** - * Module browse. - * - * @param int $rootID - * @param string $viewType story|bug|case|doc - * @param int $currentModuleID - * @access public - * @return void - */ - public function browse($rootID, $viewType, $currentModuleID = 0) - { - /* According to the type, set the module root and modules. */ - if(strpos('story|bug|case', $viewType) !== false) - { - $product = $this->loadModel('product')->getById($rootID); - $this->view->root = $product; - $this->view->productModules = $this->tree->getOptionMenu($rootID, 'story'); - } - /* The viewType is doc. */ - elseif(strpos($viewType, 'doc') !== false) - { - $this->loadModel('doc'); - if($rootID == 'product' or $rootID == 'project') - { - $viewType = $rootID . 'doc'; - $lib->id = $rootID; - $lib->name = $this->lang->doc->systemLibs[$rootID]; - $this->view->root = $lib; - } - else - { - $viewType = 'customdoc'; - $lib = $this->loadModel('doc')->getLibById($rootID); - $this->view->root = $lib; - } - } - - if($viewType == 'story') - { - $this->lang->set('menugroup.tree', 'product'); - $this->product->setMenu($this->product->getPairs(), $rootID, 'story'); - $this->lang->tree->menu = $this->lang->product->menu; - - $products = $this->product->getPairs(); - unset($products[$rootID]); - $currentProduct = key($products); - - $this->view->allProduct = $products; - $this->view->currentProduct = $currentProduct; - $this->view->productModules = $this->tree->getOptionMenu($currentProduct, 'story'); - - $header['title'] = $this->lang->tree->manageProduct . $this->lang->colon . $product->name; - $position[] = html::a($this->createLink('product', 'browse', "product=$rootID"), $product->name); - $position[] = $this->lang->tree->manageProduct; - } - elseif($viewType == 'bug') - { - $this->loadModel('bug')->setMenu($this->product->getPairs(), $rootID); - $this->lang->tree->menu = $this->lang->bug->menu; - $this->lang->set('menugroup.tree', 'qa'); - - $header['title'] = $this->lang->tree->manageBug . $this->lang->colon . $product->name; - $position[] = html::a($this->createLink('bug', 'browse', "product=$rootID"), $product->name); - $position[] = $this->lang->tree->manageBug; - } - elseif($viewType == 'case') - { - $this->loadModel('testcase')->setMenu($this->product->getPairs(), $rootID); - $this->lang->tree->menu = $this->lang->testcase->menu; - $this->lang->set('menugroup.tree', 'qa'); - - $header['title'] = $this->lang->tree->manageCase . $this->lang->colon . $product->name; - $position[] = html::a($this->createLink('testcase', 'browse', "product=$rootID"), $product->name); - $position[] = $this->lang->tree->manageCase; - } - elseif(strpos($viewType, 'doc') !== false) - { - $this->doc->setMenu($this->doc->getLibs(), $rootID, 'doc'); - $this->lang->tree->menu = $this->lang->doc->menu; - $this->lang->set('menugroup.tree', 'doc'); - - $header['title'] = $this->lang->tree->manageCustomDoc . $this->lang->colon . $lib->name; - $position[] = html::a($this->createLink('doc', 'browse', "libID=$rootID"), $lib->name); - $position[] = $this->lang->tree->manageCustomDoc; - } - - $parentModules = $this->tree->getParents($currentModuleID); - $this->view->header = $header; - $this->view->position = $position; - $this->view->rootID = $rootID; - $this->view->viewType = $viewType; - $this->view->modules = $this->tree->getTreeMenu($rootID, $viewType, $rooteModuleID = 0, array('treeModel', 'createManageLink')); - $this->view->sons = $this->tree->getSons($rootID, $currentModuleID, $viewType); - $this->view->currentModuleID = $currentModuleID; - $this->view->parentModules = $parentModules; - $this->display(); - } - - /** - * Edit a module. - * - * @param int $moduleID - * @access public - * @return void - */ - public function edit($moduleID) - { - if(!empty($_POST)) - { - $this->tree->update($moduleID); - echo js::alert($this->lang->tree->successSave); - die(js::reload('parent')); - } - $module = $this->tree->getById($moduleID); - if($module->owner == null) - { - $module->owner = $this->loadModel('product')->getById($module->root)->QM; - } - $this->view->module = $module; - $this->view->optionMenu = $this->tree->getOptionMenu($this->view->module->root, $this->view->module->type); - $this->view->users = $this->loadModel('user')->getPairs('noclosed'); - - /* Remove self and childs from the $optionMenu. Because it's parent can't be self or childs. */ - $childs = $this->tree->getAllChildId($moduleID); - foreach($childs as $childModuleID) unset($this->view->optionMenu[$childModuleID]); - - die($this->display()); - } - - /** - * Update modules' orders. - * - * @access public - * @return void - */ - public function updateOrder() - { - if(!empty($_POST)) - { - $this->tree->updateOrder($_POST['orders']); - die(js::reload('parent')); - } - } - - /** - * Manage child modules. - * - * @param int $rootID - * @param string $viewType - * @access public - * @return void - */ - public function manageChild($rootID, $viewType) - { - if(!empty($_POST)) - { - $this->tree->manageChild($rootID, $viewType, $_POST['parentModuleID'], $_POST['modules']); - die(js::reload('parent')); - } - } - - /** - * Delete a module. - * - * @param int $rootID - * @param int $moduleID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($rootID, $moduleID, $confirm = 'no') - { - if($confirm == 'no') - { - echo js::confirm($this->lang->tree->confirmDelete, $this->createLink('tree', 'delete', "rootID=$rootID&moduleID=$moduleID&confirm=yes")); - exit; - } - else - { - $this->tree->delete($moduleID); - die(js::reload('parent')); - } - } - - /** - * AJAX: Get the option menu of modules. - * - * @param int $rootID - * @param string $viewType - * @param int $rootModuleID - * @access public - * @return string the html select string. - */ - public function ajaxGetOptionMenu($rootID, $viewType = 'story', $rootModuleID = 0, $returnType = 'html') - { - - $this->view->productModules = $this->tree->getOptionMenu($rootID, 'story'); - $optionMenu = $this->tree->getOptionMenu($rootID, $viewType, $rootModuleID); - if($returnType == 'html') die( html::select("module", $optionMenu, '', 'onchange=setAssignedTo()')); - if($returnType == 'json') die(json_encode($optionMenu)); - } - - /** - * AJAX: get a module's son modules. - * - * @param int $moduleID - * @param int $rootID - * @access public - * @return string json_encoded modules. - */ - public function ajaxGetSonModules($moduleID, $rootID = 0) - { - if($moduleID) die(json_encode($this->dao->findByParent($moduleID)->from(TABLE_MODULE)->fetchPairs('id', 'name'))); - $modules = $this->dao->select('id, name')->from(TABLE_MODULE) - ->where('root')->eq($rootID) - ->andWhere('parent')->eq('0') - ->andWhere('type')->eq('story') - ->fetchPairs(); - foreach($modules as $key => $name) $modules[$key] = str_replace(" "," ","$name"); - die(json_encode($modules)); - } -} + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +class tree extends control +{ + const NEW_CHILD_COUNT = 5; + + /** + * Module browse. + * + * @param int $rootID + * @param string $viewType story|bug|case|doc + * @param int $currentModuleID + * @access public + * @return void + */ + public function browse($rootID, $viewType, $currentModuleID = 0) + { + /* According to the type, set the module root and modules. */ + if(strpos('story|bug|case', $viewType) !== false) + { + $product = $this->loadModel('product')->getById($rootID); + $this->view->root = $product; + $this->view->productModules = $this->tree->getOptionMenu($rootID, 'story'); + } + /* The viewType is doc. */ + elseif(strpos($viewType, 'doc') !== false) + { + $this->loadModel('doc'); + if($rootID == 'product' or $rootID == 'project') + { + $viewType = $rootID . 'doc'; + $lib->id = $rootID; + $lib->name = $this->lang->doc->systemLibs[$rootID]; + $this->view->root = $lib; + } + else + { + $viewType = 'customdoc'; + $lib = $this->loadModel('doc')->getLibById($rootID); + $this->view->root = $lib; + } + } + + if($viewType == 'story') + { + $this->lang->set('menugroup.tree', 'product'); + $this->product->setMenu($this->product->getPairs(), $rootID, 'story'); + $this->lang->tree->menu = $this->lang->product->menu; + + $products = $this->product->getPairs(); + unset($products[$rootID]); + $currentProduct = key($products); + + $this->view->allProduct = $products; + $this->view->currentProduct = $currentProduct; + $this->view->productModules = $this->tree->getOptionMenu($currentProduct, 'story'); + + $header['title'] = $this->lang->tree->manageProduct . $this->lang->colon . $product->name; + $position[] = html::a($this->createLink('product', 'browse', "product=$rootID"), $product->name); + $position[] = $this->lang->tree->manageProduct; + } + elseif($viewType == 'bug') + { + $this->loadModel('bug')->setMenu($this->product->getPairs(), $rootID); + $this->lang->tree->menu = $this->lang->bug->menu; + $this->lang->set('menugroup.tree', 'qa'); + + $header['title'] = $this->lang->tree->manageBug . $this->lang->colon . $product->name; + $position[] = html::a($this->createLink('bug', 'browse', "product=$rootID"), $product->name); + $position[] = $this->lang->tree->manageBug; + } + elseif($viewType == 'case') + { + $this->loadModel('testcase')->setMenu($this->product->getPairs(), $rootID); + $this->lang->tree->menu = $this->lang->testcase->menu; + $this->lang->set('menugroup.tree', 'qa'); + + $header['title'] = $this->lang->tree->manageCase . $this->lang->colon . $product->name; + $position[] = html::a($this->createLink('testcase', 'browse', "product=$rootID"), $product->name); + $position[] = $this->lang->tree->manageCase; + } + elseif(strpos($viewType, 'doc') !== false) + { + $this->doc->setMenu($this->doc->getLibs(), $rootID, 'doc'); + $this->lang->tree->menu = $this->lang->doc->menu; + $this->lang->set('menugroup.tree', 'doc'); + + $header['title'] = $this->lang->tree->manageCustomDoc . $this->lang->colon . $lib->name; + $position[] = html::a($this->createLink('doc', 'browse', "libID=$rootID"), $lib->name); + $position[] = $this->lang->tree->manageCustomDoc; + } + + $parentModules = $this->tree->getParents($currentModuleID); + $this->view->header = $header; + $this->view->position = $position; + $this->view->rootID = $rootID; + $this->view->viewType = $viewType; + $this->view->modules = $this->tree->getTreeMenu($rootID, $viewType, $rooteModuleID = 0, array('treeModel', 'createManageLink')); + $this->view->sons = $this->tree->getSons($rootID, $currentModuleID, $viewType); + $this->view->currentModuleID = $currentModuleID; + $this->view->parentModules = $parentModules; + $this->display(); + } + + /** + * Edit a module. + * + * @param int $moduleID + * @access public + * @return void + */ + public function edit($moduleID) + { + if(!empty($_POST)) + { + $this->tree->update($moduleID); + echo js::alert($this->lang->tree->successSave); + die(js::reload('parent')); + } + $module = $this->tree->getById($moduleID); + if($module->owner == null) + { + $module->owner = $this->loadModel('product')->getById($module->root)->QM; + } + $this->view->module = $module; + $this->view->optionMenu = $this->tree->getOptionMenu($this->view->module->root, $this->view->module->type); + $this->view->users = $this->loadModel('user')->getPairs('noclosed'); + + /* Remove self and childs from the $optionMenu. Because it's parent can't be self or childs. */ + $childs = $this->tree->getAllChildId($moduleID); + foreach($childs as $childModuleID) unset($this->view->optionMenu[$childModuleID]); + + die($this->display()); + } + + /** + * Update modules' orders. + * + * @access public + * @return void + */ + public function updateOrder() + { + if(!empty($_POST)) + { + $this->tree->updateOrder($_POST['orders']); + die(js::reload('parent')); + } + } + + /** + * Manage child modules. + * + * @param int $rootID + * @param string $viewType + * @access public + * @return void + */ + public function manageChild($rootID, $viewType) + { + if(!empty($_POST)) + { + $this->tree->manageChild($rootID, $viewType, $_POST['parentModuleID'], $_POST['modules']); + die(js::reload('parent')); + } + } + + /** + * Delete a module. + * + * @param int $rootID + * @param int $moduleID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($rootID, $moduleID, $confirm = 'no') + { + if($confirm == 'no') + { + echo js::confirm($this->lang->tree->confirmDelete, $this->createLink('tree', 'delete', "rootID=$rootID&moduleID=$moduleID&confirm=yes")); + exit; + } + else + { + $this->tree->delete($moduleID); + die(js::reload('parent')); + } + } + + /** + * AJAX: Get the option menu of modules. + * + * @param int $rootID + * @param string $viewType + * @param int $rootModuleID + * @access public + * @return string the html select string. + */ + public function ajaxGetOptionMenu($rootID, $viewType = 'story', $rootModuleID = 0, $returnType = 'html') + { + + $this->view->productModules = $this->tree->getOptionMenu($rootID, 'story'); + $optionMenu = $this->tree->getOptionMenu($rootID, $viewType, $rootModuleID); + if($returnType == 'html') die( html::select("module", $optionMenu, '', 'onchange=setAssignedTo()')); + if($returnType == 'json') die(json_encode($optionMenu)); + } + + /** + * AJAX: get a module's son modules. + * + * @param int $moduleID + * @param int $rootID + * @access public + * @return string json_encoded modules. + */ + public function ajaxGetSonModules($moduleID, $rootID = 0) + { + if($moduleID) die(json_encode($this->dao->findByParent($moduleID)->from(TABLE_MODULE)->fetchPairs('id', 'name'))); + $modules = $this->dao->select('id, name')->from(TABLE_MODULE) + ->where('root')->eq($rootID) + ->andWhere('parent')->eq('0') + ->andWhere('type')->eq('story') + ->fetchPairs(); + foreach($modules as $key => $name) $modules[$key] = str_replace(" "," ","$name"); + die(json_encode($modules)); + } +} diff --git a/module/tree/lang/en.php b/module/tree/lang/en.php index 5afbb34f4a..8701431137 100644 --- a/module/tree/lang/en.php +++ b/module/tree/lang/en.php @@ -1,40 +1,40 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->tree->common = 'Module manage'; -$lang->tree->add = 'Add'; -$lang->tree->edit = 'Edit'; -$lang->tree->addChild = 'Add child'; -$lang->tree->delete = 'Delete'; -$lang->tree->browse = 'Module manage'; -$lang->tree->manage = 'Manage'; -$lang->tree->docManage = 'Type'; -$lang->tree->manageProduct = 'Mange product module'; -$lang->tree->manageProject = 'Manage project module'; -$lang->tree->manageBug = 'Manage bug module'; -$lang->tree->manageCase = 'Manage case module'; -$lang->tree->manageCustomDoc = 'Manage doc library type'; -$lang->tree->updateOrder = 'Update order'; -$lang->tree->manageChild = 'Manage child'; -$lang->tree->manageDocChild = 'Manage child type'; -$lang->tree->syncFromProduct = 'Copy from product module'; -$lang->tree->ajaxGetOptionMenu = 'API: Get select menu'; -$lang->tree->ajaxGetSonModules = 'API: Get son modules'; - -$lang->tree->confirmDelete = 'Are you sure to delete this module?'; -$lang->tree->successSave = 'Success saved'; - -$lang->tree->name = 'Name'; -$lang->tree->parent = 'Parent'; -$lang->tree->child = 'Child'; -$lang->tree->owner = 'Owner'; -$lang->tree->order = 'Order'; -$lang->tree->projectDoc = 'Project doc'; + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->tree->common = 'Module manage'; +$lang->tree->add = 'Add'; +$lang->tree->edit = 'Edit'; +$lang->tree->addChild = 'Add child'; +$lang->tree->delete = 'Delete'; +$lang->tree->browse = 'Module manage'; +$lang->tree->manage = 'Manage'; +$lang->tree->docManage = 'Type'; +$lang->tree->manageProduct = 'Mange product module'; +$lang->tree->manageProject = 'Manage project module'; +$lang->tree->manageBug = 'Manage bug module'; +$lang->tree->manageCase = 'Manage case module'; +$lang->tree->manageCustomDoc = 'Manage doc library type'; +$lang->tree->updateOrder = 'Update order'; +$lang->tree->manageChild = 'Manage child'; +$lang->tree->manageDocChild = 'Manage child type'; +$lang->tree->syncFromProduct = 'Copy from product module'; +$lang->tree->ajaxGetOptionMenu = 'API: Get select menu'; +$lang->tree->ajaxGetSonModules = 'API: Get son modules'; + +$lang->tree->confirmDelete = 'Are you sure to delete this module?'; +$lang->tree->successSave = 'Success saved'; + +$lang->tree->name = 'Name'; +$lang->tree->parent = 'Parent'; +$lang->tree->child = 'Child'; +$lang->tree->owner = 'Owner'; +$lang->tree->order = 'Order'; +$lang->tree->projectDoc = 'Project doc'; diff --git a/module/tree/lang/zh-cn.php b/module/tree/lang/zh-cn.php index f8e34e59c2..9fbde665c4 100644 --- a/module/tree/lang/zh-cn.php +++ b/module/tree/lang/zh-cn.php @@ -1,40 +1,40 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->tree->common = '模块维护'; -$lang->tree->add = '添加'; -$lang->tree->edit = '编辑'; -$lang->tree->addChild = '添加子模块'; -$lang->tree->delete = '删除模块'; -$lang->tree->browse = '模块维护'; -$lang->tree->manage = '维护模块'; -$lang->tree->docManage = '分类'; -$lang->tree->manageProduct = '维护产品视图模块'; -$lang->tree->manageProject = '维护项目视图模块'; -$lang->tree->manageBug = '维护测试视图模块'; -$lang->tree->manageCase = '维护用例视图模块'; -$lang->tree->manageCustomDoc = '维护文档库分类'; -$lang->tree->updateOrder = '更新排序'; -$lang->tree->manageChild = '维护子模块'; -$lang->tree->manageDocChild = '维护分类'; -$lang->tree->syncFromProduct = '复制产品视图模块'; -$lang->tree->ajaxGetOptionMenu = '接口:获取下拉列表'; -$lang->tree->ajaxGetSonModules = '接口:获得子菜单列表'; - -$lang->tree->confirmDelete = '您确定删除该模块吗?'; -$lang->tree->successSave = '成功保存'; - -$lang->tree->name = '模块名称'; -$lang->tree->parent = '上级模块'; -$lang->tree->child = '子模块'; -$lang->tree->owner = '负责人'; -$lang->tree->order = '排序'; -$lang->tree->projectDoc = '项目文档'; + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->tree->common = '模块维护'; +$lang->tree->add = '添加'; +$lang->tree->edit = '编辑'; +$lang->tree->addChild = '添加子模块'; +$lang->tree->delete = '删除模块'; +$lang->tree->browse = '模块维护'; +$lang->tree->manage = '维护模块'; +$lang->tree->docManage = '分类'; +$lang->tree->manageProduct = '维护产品视图模块'; +$lang->tree->manageProject = '维护项目视图模块'; +$lang->tree->manageBug = '维护测试视图模块'; +$lang->tree->manageCase = '维护用例视图模块'; +$lang->tree->manageCustomDoc = '维护文档库分类'; +$lang->tree->updateOrder = '更新排序'; +$lang->tree->manageChild = '维护子模块'; +$lang->tree->manageDocChild = '维护分类'; +$lang->tree->syncFromProduct = '复制产品视图模块'; +$lang->tree->ajaxGetOptionMenu = '接口:获取下拉列表'; +$lang->tree->ajaxGetSonModules = '接口:获得子菜单列表'; + +$lang->tree->confirmDelete = '您确定删除该模块吗?'; +$lang->tree->successSave = '成功保存'; + +$lang->tree->name = '模块名称'; +$lang->tree->parent = '上级模块'; +$lang->tree->child = '子模块'; +$lang->tree->owner = '负责人'; +$lang->tree->order = '排序'; +$lang->tree->projectDoc = '项目文档'; diff --git a/module/tree/lang/zh-tw.php b/module/tree/lang/zh-tw.php index 101d9b8458..f1ea6d7933 100644 --- a/module/tree/lang/zh-tw.php +++ b/module/tree/lang/zh-tw.php @@ -1,40 +1,40 @@ - - * @package tree - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->tree->common = '模組維護'; -$lang->tree->add = '添加'; -$lang->tree->edit = '編輯'; -$lang->tree->addChild = '添加子模組'; -$lang->tree->delete = '刪除模組'; -$lang->tree->browse = '模組維護'; -$lang->tree->manage = '維護模組'; -$lang->tree->docManage = '分類'; -$lang->tree->manageProduct = '維護產品視圖模組'; -$lang->tree->manageProject = '維護項目視圖模組'; -$lang->tree->manageBug = '維護測試視圖模組'; -$lang->tree->manageCase = '維護用例視圖模組'; -$lang->tree->manageCustomDoc = '維護文檔庫分類'; -$lang->tree->updateOrder = '更新排序'; -$lang->tree->manageChild = '維護子模組'; -$lang->tree->manageDocChild = '維護分類'; -$lang->tree->syncFromProduct = '複製產品視圖模組'; -$lang->tree->ajaxGetOptionMenu = '介面:獲取下拉列表'; -$lang->tree->ajaxGetSonModules = '介面:獲得子菜單列表'; - -$lang->tree->confirmDelete = '您確定刪除該模組嗎?'; -$lang->tree->successSave = '成功保存'; - -$lang->tree->name = '模組名稱'; -$lang->tree->parent = '上級模組'; -$lang->tree->child = '子模組'; -$lang->tree->owner = '負責人'; -$lang->tree->order = '排序'; -$lang->tree->projectDoc = '項目文檔'; + + * @package tree + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->tree->common = '模組維護'; +$lang->tree->add = '添加'; +$lang->tree->edit = '編輯'; +$lang->tree->addChild = '添加子模組'; +$lang->tree->delete = '刪除模組'; +$lang->tree->browse = '模組維護'; +$lang->tree->manage = '維護模組'; +$lang->tree->docManage = '分類'; +$lang->tree->manageProduct = '維護產品視圖模組'; +$lang->tree->manageProject = '維護項目視圖模組'; +$lang->tree->manageBug = '維護測試視圖模組'; +$lang->tree->manageCase = '維護用例視圖模組'; +$lang->tree->manageCustomDoc = '維護文檔庫分類'; +$lang->tree->updateOrder = '更新排序'; +$lang->tree->manageChild = '維護子模組'; +$lang->tree->manageDocChild = '維護分類'; +$lang->tree->syncFromProduct = '複製產品視圖模組'; +$lang->tree->ajaxGetOptionMenu = '介面:獲取下拉列表'; +$lang->tree->ajaxGetSonModules = '介面:獲得子菜單列表'; + +$lang->tree->confirmDelete = '您確定刪除該模組嗎?'; +$lang->tree->successSave = '成功保存'; + +$lang->tree->name = '模組名稱'; +$lang->tree->parent = '上級模組'; +$lang->tree->child = '子模組'; +$lang->tree->owner = '負責人'; +$lang->tree->order = '排序'; +$lang->tree->projectDoc = '項目文檔'; diff --git a/module/tree/model.php b/module/tree/model.php index e8c6200a1f..00ce7d3552 100644 --- a/module/tree/model.php +++ b/module/tree/model.php @@ -1,547 +1,547 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -?> -dao->findById((int)$moduleID)->from(TABLE_MODULE)->fetch(); - } - - /** - * Build the sql query. - * - * @param int $rootID - * @param string $type - * @param int $startModule - * @access public - * @return void - */ - public function buildMenuQuery($rootID, $type, $startModule) - { - /* Set the start module. */ - $startModulePath = ''; - if($startModule > 0) - { - $startModule = $this->getById($startModule); - if($startModule) $startModulePath = $startModule->path . '%'; - } - - return $this->dao->select('*')->from(TABLE_MODULE) - ->where('root')->eq((int)$rootID) - ->andWhere('type')->eq($type) - ->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi() - ->orderBy('grade desc, `order`') - ->get(); - } - - /** - * Create an option menu in html. - * - * @param int $rootID - * @param string $type - * @param int $startModule - * @access public - * @return string - */ - public function getOptionMenu($rootID, $type = 'story', $startModule = 0) - { - $treeMenu = array(); - $stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule)); - $modules = array(); - while($module = $stmt->fetch()) $modules[$module->id] = $module; - - foreach($modules as $module) - { - $parentModules = explode(',', $module->path); - $moduleName = '/'; - foreach($parentModules as $parentModuleID) - { - if(empty($parentModuleID)) continue; - $moduleName .= $modules[$parentModuleID]->name . '/'; - } - $moduleName = rtrim($moduleName, '/'); - $moduleName .= "|$module->id\n"; - - if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id])) - { - if(isset($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= $moduleName; - } - else - { - $treeMenu[$module->parent] = $moduleName;; - } - $treeMenu[$module->parent] .= $treeMenu[$module->id]; - } - else - { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= $moduleName; - } - else - { - $treeMenu[$module->parent] = $moduleName; - } - } - } - - $topMenu = @array_pop($treeMenu); - $topMenu = explode("\n", trim($topMenu)); - $lastMenu[] = '/'; - foreach($topMenu as $menu) - { - if(!strpos($menu, '|')) continue; - list($label, $moduleID) = explode('|', $menu); - $lastMenu[$moduleID] = $label; - } - return $lastMenu; - } - - /** - * Get the tree menu in html. - * - * @param int $rootID - * @param string $type - * @param int $startModule - * @param string $userFunc the function used to create link - * @param string $extra extra params - * @access public - * @return string - */ - public function getTreeMenu($rootID, $type = 'root', $startModule = 0, $userFunc, $extra = '') - { - $treeMenu = array(); - $stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule)); - while($module = $stmt->fetch()) - { - $linkHtml = call_user_func($userFunc, $module, $extra); - - if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id])) - { - if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = ''; - $treeMenu[$module->parent] .= "
        • $linkHtml"; - $treeMenu[$module->parent] .= "
            ".$treeMenu[$module->id]."
          \n"; - } - else - { - if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) - { - $treeMenu[$module->parent] .= "
        • $linkHtml\n"; - } - else - { - $treeMenu[$module->parent] = "
        • $linkHtml\n"; - } - } - $treeMenu[$module->parent] .= "
        • \n"; - } - - $lastMenu = "
            " . @array_pop($treeMenu) . "
          \n"; - return $lastMenu; - } - - /** - * Get the tree menu of product document library. - * - * @access public - * @return string - */ - public function getProductDocTreeMenu() - { - $menu = "
            "; - $products = $this->loadModel('product')->getPairs('nocode'); - $modules = $this->dao->findByType('productdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); - $projectModules = $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); - - foreach($products as $productID =>$productName) - { - $menu .= '
          • '; - $menu .= html::a(helper::createLink('doc', 'browse', "libID=product&module=0&productID=$productID"), $productName); - if($modules) - { - $menu .= '
              '; - foreach($modules as $module) - { - $menu .= '
            • ' . html::a(helper::createLink('doc', 'browse', "libID=product&module=$module->id&productID=$productID"), $module->name) . '
            • '; - } - - /* If $projectModules not emtpy, append the project modules. */ - if($projectModules) - { - $menu .= '
            • '; - $menu .= html::a(helper::createLink('doc', 'browse', "libID=product&module=0&productID=$productID&projectID=int"), $this->lang->tree->projectDoc); - $menu .= '
                '; - foreach($projectModules as $module) - { - $menu .= '
              • ' . html::a(helper::createLink('doc', 'browse', "libID=product&module=$module->id&productID=$productID"), $module->name) . '
              • '; - } - $menu .= '
            • '; - } - - $menu .= '
            '; - } - } - - $menu .= '
          • '; - return $menu; - } - - /** - * Get the tree menu of project document library. - * - * @access public - * @return void - */ - public function getProjectDocTreeMenu() - { - $menu = "
              "; - $products = $this->loadModel('product')->getPairs('nocode'); - $projects = $this->loadModel('project')->getProductGroupList(); - $modules = $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); - $products[0] = $this->lang->project->noProduct; - foreach($projects as $id => $project) - { - if($id == '') - { - $projects[0] = $projects['']; - unset($projects['']); - } - } - - foreach($products as $productID => $productName) - { - $menu .= '
            • '; - $menu .= $productName; - - if(isset($projects[$productID])) - { - $menu .= '
                '; - foreach($projects[$productID] as $project) - { - $menu .= '
              • ' . html::a(helper::createLink('doc', 'browse', "libID=project&module=0&productID=0&projectID=$project->id"), $project->name); - if($modules) - { - $menu .= '
                  '; - foreach($modules as $module) - { - $menu .= '
                • ' . html::a(helper::createLink('doc', 'browse', "libID=project&module=$module->id&productID=0&projectID=$project->id"), $module->name) . '
                • '; - } - $menu .= '
                '; - } - $menu .= '
              • '; - } - $menu .='
              '; - } - $menu .='
            • '; - } - - $menu .= '
            '; - return $menu; - } - - /** - * Create link of a story. - * - * @param object $module - * @access public - * @return string - */ - public function createStoryLink($module) - { - $linkHtml = html::a(helper::createLink('product', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); - return $linkHtml; - } - - /** - * Create link of a doc. - * - * @param object $module - * @access public - * @return string - */ - public function createDocLink($module) - { - $linkHtml = html::a(helper::createLink('doc', 'browse', "libID={$module->root}&&module={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); - return $linkHtml; - } - - /** - * Create the manage link of a module. - * - * @param object $module - * @access public - * @return string - */ - public function createManageLink($module) - { - static $users; - if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter'); - $linkHtml = $module->name; - if($module->type == 'bug' and $module->owner) $linkHtml .= '[' . $users[$module->owner] . ']'; - if(common::hasPriv('tree', 'edit')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}"), $this->lang->tree->edit, '', 'class="iframe"'); - if(common::hasPriv('tree', 'browse') and strpos('productdoc,projectdoc', $module->type) === false) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type={$module->type}&module={$module->id}"), $this->lang->tree->child); - if(common::hasPriv('tree', 'delete')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'delete', "root={$module->root}&module={$module->id}"), $this->lang->delete, 'hiddenwin'); - if(common::hasPriv('tree', 'updateorder')) $linkHtml .= ' ' . html::input("orders[$module->id]", $module->order, 'style="width:30px;text-align:center"'); - return $linkHtml; - } - - /** - * Create link of a bug. - * - * @param object $module - * @access public - * @return string - */ - public function createBugLink($module) - { - $linkHtml = html::a(helper::createLink('bug', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); - return $linkHtml; - } - - /** - * Create link of a test case. - * - * @param object $module - * @access public - * @return string - */ - public function createCaseLink($module) - { - $linkHtml = html::a(helper::createLink('testcase', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); - return $linkHtml; - } - - /** - * Create link of a test task. - * - * @param object $module - * @access public - * @return string - */ - public function createTestTaskLink($module, $extra) - { - $linkHtml = html::a(helper::createLink('testtask', 'cases', "taskID=$extra&type=byModule&module={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); - return $linkHtml; - } - - /** - * Get sons of a module. - * - * @param int $rootID - * @param int $moduleID - * @param string $type - * @access public - * @return array - */ - public function getSons($rootID, $moduleID, $type = 'root') - { - return $this->dao->select('*')->from(TABLE_MODULE) - ->where('root')->eq((int)$rootID) - ->andWhere('parent')->eq((int)$moduleID) - ->andWhere('type')->eq($type) - ->orderBy('`order`') - ->fetchAll(); - } - - /** - * Get id list of a module's childs. - * - * @param int $moduleID - * @access public - * @return array - */ - public function getAllChildId($moduleID) - { - if($moduleID == 0) return array(); - $module = $this->getById((int)$moduleID); - return $this->dao->select('id')->from(TABLE_MODULE)->where('path')->like($module->path . '%')->fetchPairs(); - } - - /** - * Get parents of a module. - * - * @param int $moduleID - * @access public - * @return array - */ - public function getParents($moduleID) - { - if($moduleID == 0) return array(); - $path = $this->dao->select('path')->from(TABLE_MODULE)->where('id')->eq((int)$moduleID)->fetch('path'); - $path = trim($path, ','); - if(!$path) return array(); - return $this->dao->select('*')->from(TABLE_MODULE)->where('id')->in($path)->orderBy('grade')->fetchAll(); - } - - /** - * Update modules' order. - * - * @param array $orders - * @access public - * @return void - */ - public function updateOrder($orders) - { - foreach($orders as $moduleID => $order) - { - $this->dao->update(TABLE_MODULE)->set('`order`')->eq($order)->where('id')->eq((int)$moduleID)->limit(1)->exec(); - } - } - - /** - * Manage childs of a module. - * - * @param int $rootID - * @param string $type - * @param int $parentModuleID - * @param array $childs - * @access public - * @return void - */ - public function manageChild($rootID, $type, $parentModuleID, $childs) - { - $parentModule = $this->getByID($parentModuleID); - if($parentModule) - { - $grade = $parentModule->grade + 1; - $parentPath = $parentModule->path; - } - else - { - $grade = 1; - $parentPath = ','; - } - $i = 1; - foreach($childs as $moduleID => $moduleName) - { - if(empty($moduleName)) continue; - - /* The new modules. */ - if(is_numeric($moduleID)) - { - $module->root = $rootID; - $module->name = strip_tags($moduleName); - $module->parent = $parentModuleID; - $module->grade = $grade; - $module->type = $type; - $module->order = $this->post->maxOrder + $i * 10; - $this->dao->insert(TABLE_MODULE)->data($module)->exec(); - $moduleID = $this->dao->lastInsertID(); - $childPath = $parentPath . "$moduleID,"; - $this->dao->update(TABLE_MODULE)->set('path')->eq($childPath)->where('id')->eq($moduleID)->limit(1)->exec(); - $i ++; - } - else - { - $moduleID = str_replace('id', '', $moduleID); - $this->dao->update(TABLE_MODULE)->set('name')->eq(strip_tags($moduleName))->where('id')->eq($moduleID)->limit(1)->exec(); - } - } - } - - /** - * Update a module. - * - * @param int $moduleID - * @access public - * @return void - */ - public function update($moduleID) - { - $module = fixer::input('post')->specialChars('name')->get(); - $self = $this->getById($moduleID); - $parent = $this->getById($this->post->parent); - $childs = $this->getAllChildId($moduleID); - $module->grade = $parent ? $parent->grade + 1 : 1; - $this->dao->update(TABLE_MODULE)->data($module)->autoCheck()->check('name', 'notempty')->where('id')->eq($moduleID)->exec(); - $this->dao->update(TABLE_MODULE)->set('grade = grade + 1')->where('id')->in($childs)->andWhere('id')->ne($moduleID)->exec(); - $this->dao->update(TABLE_MODULE)->set('owner')->eq($this->post->owner)->where('id')->in($childs)->andWhere('owner')->eq('')->exec(); - $this->dao->update(TABLE_MODULE)->set('owner')->eq($this->post->owner)->where('id')->in($childs)->andWhere('owner')->eq($self->owner)->exec(); - $this->fixModulePath(); - } - - /** - * Delete a module. - * - * @param int $moduleID - * @access public - * @return void - */ - public function delete($moduleID) - { - $module = $this->getById($moduleID); - $childs = $this->getAllChildId($moduleID); - - $this->dao->update(TABLE_MODULE)->set('grade = grade - 1')->where('id')->in($childs)->exec(); // Update grade of all childs. - $this->dao->update(TABLE_MODULE)->set('parent')->eq($module->parent)->where('parent')->eq($moduleID)->exec(); // Update the parent of sons to my parent. - $this->dao->delete()->from(TABLE_MODULE)->where('id')->eq($moduleID)->exec(); // Delete my self. - $this->fixModulePath(); - - if($module->type == 'story') $this->dao->update(TABLE_STORY)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); - if($module->type == 'bug') $this->dao->update(TABLE_BUG)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); - if($module->type == 'case') $this->dao->update(TABLE_CASE)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); - } - - /** - * Fix fieilds of all module, grade, parent, pathes and so on. - * - * @access public - * @return void - */ - public function fixModulePath() - { - /* Get the max grade. */ - $maxGrade = $this->dao->select('MAX(grade) AS grade')->from(TABLE_MODULE)->fetch('grade'); - $modules = array(); - - /* Cycle ervery grade. */ - for($grade = 1; $grade <= $maxGrade; $grade ++) - { - /* Modules of current grade. */ - $gradeModules = $this->dao->select('id, parent, grade')->from(TABLE_MODULE)->where('grade')->eq($grade)->fetchAll('id'); - foreach($gradeModules as $moduleID => $module) - { - if($grade == 1) - { - $module->path = ",$moduleID,"; - } - else - { - /* Get the parent module to compute path and grade of my self. */ - if(isset($modules[$module->parent])) - { - $module->path = $modules[$module->parent]->path . "$moduleID,"; - $module->grade = $modules[$module->parent]->grade + 1; - } - } - } - $modules += $gradeModules; - } - - /* Save modules to database. */ - foreach($modules as $moduleID => $module) - { - $this->dao->update(TABLE_MODULE)->data($module)->where('id')->eq($module->id)->limit(1)->exec(); - } - } -} + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +?> +dao->findById((int)$moduleID)->from(TABLE_MODULE)->fetch(); + } + + /** + * Build the sql query. + * + * @param int $rootID + * @param string $type + * @param int $startModule + * @access public + * @return void + */ + public function buildMenuQuery($rootID, $type, $startModule) + { + /* Set the start module. */ + $startModulePath = ''; + if($startModule > 0) + { + $startModule = $this->getById($startModule); + if($startModule) $startModulePath = $startModule->path . '%'; + } + + return $this->dao->select('*')->from(TABLE_MODULE) + ->where('root')->eq((int)$rootID) + ->andWhere('type')->eq($type) + ->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi() + ->orderBy('grade desc, `order`') + ->get(); + } + + /** + * Create an option menu in html. + * + * @param int $rootID + * @param string $type + * @param int $startModule + * @access public + * @return string + */ + public function getOptionMenu($rootID, $type = 'story', $startModule = 0) + { + $treeMenu = array(); + $stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule)); + $modules = array(); + while($module = $stmt->fetch()) $modules[$module->id] = $module; + + foreach($modules as $module) + { + $parentModules = explode(',', $module->path); + $moduleName = '/'; + foreach($parentModules as $parentModuleID) + { + if(empty($parentModuleID)) continue; + $moduleName .= $modules[$parentModuleID]->name . '/'; + } + $moduleName = rtrim($moduleName, '/'); + $moduleName .= "|$module->id\n"; + + if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id])) + { + if(isset($treeMenu[$module->parent])) + { + $treeMenu[$module->parent] .= $moduleName; + } + else + { + $treeMenu[$module->parent] = $moduleName;; + } + $treeMenu[$module->parent] .= $treeMenu[$module->id]; + } + else + { + if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) + { + $treeMenu[$module->parent] .= $moduleName; + } + else + { + $treeMenu[$module->parent] = $moduleName; + } + } + } + + $topMenu = @array_pop($treeMenu); + $topMenu = explode("\n", trim($topMenu)); + $lastMenu[] = '/'; + foreach($topMenu as $menu) + { + if(!strpos($menu, '|')) continue; + list($label, $moduleID) = explode('|', $menu); + $lastMenu[$moduleID] = $label; + } + return $lastMenu; + } + + /** + * Get the tree menu in html. + * + * @param int $rootID + * @param string $type + * @param int $startModule + * @param string $userFunc the function used to create link + * @param string $extra extra params + * @access public + * @return string + */ + public function getTreeMenu($rootID, $type = 'root', $startModule = 0, $userFunc, $extra = '') + { + $treeMenu = array(); + $stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule)); + while($module = $stmt->fetch()) + { + $linkHtml = call_user_func($userFunc, $module, $extra); + + if(isset($treeMenu[$module->id]) and !empty($treeMenu[$module->id])) + { + if(!isset($treeMenu[$module->parent])) $treeMenu[$module->parent] = ''; + $treeMenu[$module->parent] .= "
          • $linkHtml"; + $treeMenu[$module->parent] .= "
              ".$treeMenu[$module->id]."
            \n"; + } + else + { + if(isset($treeMenu[$module->parent]) and !empty($treeMenu[$module->parent])) + { + $treeMenu[$module->parent] .= "
          • $linkHtml\n"; + } + else + { + $treeMenu[$module->parent] = "
          • $linkHtml\n"; + } + } + $treeMenu[$module->parent] .= "
          • \n"; + } + + $lastMenu = "
              " . @array_pop($treeMenu) . "
            \n"; + return $lastMenu; + } + + /** + * Get the tree menu of product document library. + * + * @access public + * @return string + */ + public function getProductDocTreeMenu() + { + $menu = "
              "; + $products = $this->loadModel('product')->getPairs('nocode'); + $modules = $this->dao->findByType('productdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); + $projectModules = $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); + + foreach($products as $productID =>$productName) + { + $menu .= '
            • '; + $menu .= html::a(helper::createLink('doc', 'browse', "libID=product&module=0&productID=$productID"), $productName); + if($modules) + { + $menu .= '
                '; + foreach($modules as $module) + { + $menu .= '
              • ' . html::a(helper::createLink('doc', 'browse', "libID=product&module=$module->id&productID=$productID"), $module->name) . '
              • '; + } + + /* If $projectModules not emtpy, append the project modules. */ + if($projectModules) + { + $menu .= '
              • '; + $menu .= html::a(helper::createLink('doc', 'browse', "libID=product&module=0&productID=$productID&projectID=int"), $this->lang->tree->projectDoc); + $menu .= '
                  '; + foreach($projectModules as $module) + { + $menu .= '
                • ' . html::a(helper::createLink('doc', 'browse', "libID=product&module=$module->id&productID=$productID"), $module->name) . '
                • '; + } + $menu .= '
              • '; + } + + $menu .= '
              '; + } + } + + $menu .= '
            • '; + return $menu; + } + + /** + * Get the tree menu of project document library. + * + * @access public + * @return void + */ + public function getProjectDocTreeMenu() + { + $menu = "
                "; + $products = $this->loadModel('product')->getPairs('nocode'); + $projects = $this->loadModel('project')->getProductGroupList(); + $modules = $this->dao->findByType('projectdoc')->from(TABLE_MODULE)->orderBy('`order`')->fetchAll(); + $products[0] = $this->lang->project->noProduct; + foreach($projects as $id => $project) + { + if($id == '') + { + $projects[0] = $projects['']; + unset($projects['']); + } + } + + foreach($products as $productID => $productName) + { + $menu .= '
              • '; + $menu .= $productName; + + if(isset($projects[$productID])) + { + $menu .= '
                  '; + foreach($projects[$productID] as $project) + { + $menu .= '
                • ' . html::a(helper::createLink('doc', 'browse', "libID=project&module=0&productID=0&projectID=$project->id"), $project->name); + if($modules) + { + $menu .= '
                    '; + foreach($modules as $module) + { + $menu .= '
                  • ' . html::a(helper::createLink('doc', 'browse', "libID=project&module=$module->id&productID=0&projectID=$project->id"), $module->name) . '
                  • '; + } + $menu .= '
                  '; + } + $menu .= '
                • '; + } + $menu .='
                '; + } + $menu .='
              • '; + } + + $menu .= '
              '; + return $menu; + } + + /** + * Create link of a story. + * + * @param object $module + * @access public + * @return string + */ + public function createStoryLink($module) + { + $linkHtml = html::a(helper::createLink('product', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); + return $linkHtml; + } + + /** + * Create link of a doc. + * + * @param object $module + * @access public + * @return string + */ + public function createDocLink($module) + { + $linkHtml = html::a(helper::createLink('doc', 'browse', "libID={$module->root}&&module={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); + return $linkHtml; + } + + /** + * Create the manage link of a module. + * + * @param object $module + * @access public + * @return string + */ + public function createManageLink($module) + { + static $users; + if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter'); + $linkHtml = $module->name; + if($module->type == 'bug' and $module->owner) $linkHtml .= '[' . $users[$module->owner] . ']'; + if(common::hasPriv('tree', 'edit')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'edit', "module={$module->id}"), $this->lang->tree->edit, '', 'class="iframe"'); + if(common::hasPriv('tree', 'browse') and strpos('productdoc,projectdoc', $module->type) === false) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'browse', "root={$module->root}&type={$module->type}&module={$module->id}"), $this->lang->tree->child); + if(common::hasPriv('tree', 'delete')) $linkHtml .= ' ' . html::a(helper::createLink('tree', 'delete', "root={$module->root}&module={$module->id}"), $this->lang->delete, 'hiddenwin'); + if(common::hasPriv('tree', 'updateorder')) $linkHtml .= ' ' . html::input("orders[$module->id]", $module->order, 'style="width:30px;text-align:center"'); + return $linkHtml; + } + + /** + * Create link of a bug. + * + * @param object $module + * @access public + * @return string + */ + public function createBugLink($module) + { + $linkHtml = html::a(helper::createLink('bug', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); + return $linkHtml; + } + + /** + * Create link of a test case. + * + * @param object $module + * @access public + * @return string + */ + public function createCaseLink($module) + { + $linkHtml = html::a(helper::createLink('testcase', 'browse', "root={$module->root}&type=byModule¶m={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); + return $linkHtml; + } + + /** + * Create link of a test task. + * + * @param object $module + * @access public + * @return string + */ + public function createTestTaskLink($module, $extra) + { + $linkHtml = html::a(helper::createLink('testtask', 'cases', "taskID=$extra&type=byModule&module={$module->id}"), $module->name, '_self', "id='module{$module->id}'"); + return $linkHtml; + } + + /** + * Get sons of a module. + * + * @param int $rootID + * @param int $moduleID + * @param string $type + * @access public + * @return array + */ + public function getSons($rootID, $moduleID, $type = 'root') + { + return $this->dao->select('*')->from(TABLE_MODULE) + ->where('root')->eq((int)$rootID) + ->andWhere('parent')->eq((int)$moduleID) + ->andWhere('type')->eq($type) + ->orderBy('`order`') + ->fetchAll(); + } + + /** + * Get id list of a module's childs. + * + * @param int $moduleID + * @access public + * @return array + */ + public function getAllChildId($moduleID) + { + if($moduleID == 0) return array(); + $module = $this->getById((int)$moduleID); + return $this->dao->select('id')->from(TABLE_MODULE)->where('path')->like($module->path . '%')->fetchPairs(); + } + + /** + * Get parents of a module. + * + * @param int $moduleID + * @access public + * @return array + */ + public function getParents($moduleID) + { + if($moduleID == 0) return array(); + $path = $this->dao->select('path')->from(TABLE_MODULE)->where('id')->eq((int)$moduleID)->fetch('path'); + $path = trim($path, ','); + if(!$path) return array(); + return $this->dao->select('*')->from(TABLE_MODULE)->where('id')->in($path)->orderBy('grade')->fetchAll(); + } + + /** + * Update modules' order. + * + * @param array $orders + * @access public + * @return void + */ + public function updateOrder($orders) + { + foreach($orders as $moduleID => $order) + { + $this->dao->update(TABLE_MODULE)->set('`order`')->eq($order)->where('id')->eq((int)$moduleID)->limit(1)->exec(); + } + } + + /** + * Manage childs of a module. + * + * @param int $rootID + * @param string $type + * @param int $parentModuleID + * @param array $childs + * @access public + * @return void + */ + public function manageChild($rootID, $type, $parentModuleID, $childs) + { + $parentModule = $this->getByID($parentModuleID); + if($parentModule) + { + $grade = $parentModule->grade + 1; + $parentPath = $parentModule->path; + } + else + { + $grade = 1; + $parentPath = ','; + } + $i = 1; + foreach($childs as $moduleID => $moduleName) + { + if(empty($moduleName)) continue; + + /* The new modules. */ + if(is_numeric($moduleID)) + { + $module->root = $rootID; + $module->name = strip_tags($moduleName); + $module->parent = $parentModuleID; + $module->grade = $grade; + $module->type = $type; + $module->order = $this->post->maxOrder + $i * 10; + $this->dao->insert(TABLE_MODULE)->data($module)->exec(); + $moduleID = $this->dao->lastInsertID(); + $childPath = $parentPath . "$moduleID,"; + $this->dao->update(TABLE_MODULE)->set('path')->eq($childPath)->where('id')->eq($moduleID)->limit(1)->exec(); + $i ++; + } + else + { + $moduleID = str_replace('id', '', $moduleID); + $this->dao->update(TABLE_MODULE)->set('name')->eq(strip_tags($moduleName))->where('id')->eq($moduleID)->limit(1)->exec(); + } + } + } + + /** + * Update a module. + * + * @param int $moduleID + * @access public + * @return void + */ + public function update($moduleID) + { + $module = fixer::input('post')->specialChars('name')->get(); + $self = $this->getById($moduleID); + $parent = $this->getById($this->post->parent); + $childs = $this->getAllChildId($moduleID); + $module->grade = $parent ? $parent->grade + 1 : 1; + $this->dao->update(TABLE_MODULE)->data($module)->autoCheck()->check('name', 'notempty')->where('id')->eq($moduleID)->exec(); + $this->dao->update(TABLE_MODULE)->set('grade = grade + 1')->where('id')->in($childs)->andWhere('id')->ne($moduleID)->exec(); + $this->dao->update(TABLE_MODULE)->set('owner')->eq($this->post->owner)->where('id')->in($childs)->andWhere('owner')->eq('')->exec(); + $this->dao->update(TABLE_MODULE)->set('owner')->eq($this->post->owner)->where('id')->in($childs)->andWhere('owner')->eq($self->owner)->exec(); + $this->fixModulePath(); + } + + /** + * Delete a module. + * + * @param int $moduleID + * @access public + * @return void + */ + public function delete($moduleID) + { + $module = $this->getById($moduleID); + $childs = $this->getAllChildId($moduleID); + + $this->dao->update(TABLE_MODULE)->set('grade = grade - 1')->where('id')->in($childs)->exec(); // Update grade of all childs. + $this->dao->update(TABLE_MODULE)->set('parent')->eq($module->parent)->where('parent')->eq($moduleID)->exec(); // Update the parent of sons to my parent. + $this->dao->delete()->from(TABLE_MODULE)->where('id')->eq($moduleID)->exec(); // Delete my self. + $this->fixModulePath(); + + if($module->type == 'story') $this->dao->update(TABLE_STORY)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); + if($module->type == 'bug') $this->dao->update(TABLE_BUG)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); + if($module->type == 'case') $this->dao->update(TABLE_CASE)->set('module')->eq($module->parent)->where('module')->eq($moduleID)->exec(); + } + + /** + * Fix fieilds of all module, grade, parent, pathes and so on. + * + * @access public + * @return void + */ + public function fixModulePath() + { + /* Get the max grade. */ + $maxGrade = $this->dao->select('MAX(grade) AS grade')->from(TABLE_MODULE)->fetch('grade'); + $modules = array(); + + /* Cycle ervery grade. */ + for($grade = 1; $grade <= $maxGrade; $grade ++) + { + /* Modules of current grade. */ + $gradeModules = $this->dao->select('id, parent, grade')->from(TABLE_MODULE)->where('grade')->eq($grade)->fetchAll('id'); + foreach($gradeModules as $moduleID => $module) + { + if($grade == 1) + { + $module->path = ",$moduleID,"; + } + else + { + /* Get the parent module to compute path and grade of my self. */ + if(isset($modules[$module->parent])) + { + $module->path = $modules[$module->parent]->path . "$moduleID,"; + $module->grade = $modules[$module->parent]->grade + 1; + } + } + } + $modules += $gradeModules; + } + + /* Save modules to database. */ + foreach($modules as $moduleID => $module) + { + $this->dao->update(TABLE_MODULE)->data($module)->where('id')->eq($module->id)->limit(1)->exec(); + } + } +} diff --git a/module/tree/view/browse.html.php b/module/tree/view/browse.html.php index 7057c1754d..f73a007a17 100644 --- a/module/tree/view/browse.html.php +++ b/module/tree/view/browse.html.php @@ -1,96 +1,96 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - -
              -
              id}&viewType=$viewType");?>'> - - - - - -
              title;?>
              -
              -
              - tree->updateOrder);?> -
              -
              -
              -
              -
              id}&viewType=$viewType");?>'> - - - - - - - - - -
              tree->manageDocChild : $lang->tree->manageChild;?>
              - - createLink('tree', 'browse', "root={$root->id}&viewType=$viewType"), $root->name); - echo $lang->arrow; - foreach($parentModules as $module) - { - echo html::a($this->createLink('tree', 'browse', "root={$root->id}&viewType=$viewType&moduleID=$module->id"), $module->name); - echo $lang->arrow; - } - ?> - - - tree->syncFromProduct, 'onclick=syncModule('.$rootID.')'); - echo '
              '; - } - else if($viewType == 'story') - { - if($allProduct) - { - echo html::select('allProduct', $allProduct, '', 'onchange=syncProduct(this)'); - echo html::select('productModule', $productModules, ''); - echo html::commonButton($lang->tree->syncFromProduct, 'id=copyModule onclick=syncModule('.$currentProduct.')'); - } - echo '
              '; - } - $maxOrder = 0; - echo '
              '; - foreach($sons as $sonModule) - { - if($sonModule->order > $maxOrder) $maxOrder = $sonModule->order; - echo '' . html::input("modules[id$sonModule->id]", $sonModule->name, 'class=text-3 style="margin-bottom:5px"') . '
              '; - } - for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++) echo '' . html::input("modules[]", '', 'class=text-3 style="margin-bottom:5px"') . '
              '; - ?> -
              -
              - - -
              -
              -
              - + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + +
              +
              id}&viewType=$viewType");?>'> + + + + + +
              title;?>
              +
              +
              + tree->updateOrder);?> +
              +
              +
              +
              +
              id}&viewType=$viewType");?>'> + + + + + + + + + +
              tree->manageDocChild : $lang->tree->manageChild;?>
              + + createLink('tree', 'browse', "root={$root->id}&viewType=$viewType"), $root->name); + echo $lang->arrow; + foreach($parentModules as $module) + { + echo html::a($this->createLink('tree', 'browse', "root={$root->id}&viewType=$viewType&moduleID=$module->id"), $module->name); + echo $lang->arrow; + } + ?> + + + tree->syncFromProduct, 'onclick=syncModule('.$rootID.')'); + echo '
              '; + } + else if($viewType == 'story') + { + if($allProduct) + { + echo html::select('allProduct', $allProduct, '', 'onchange=syncProduct(this)'); + echo html::select('productModule', $productModules, ''); + echo html::commonButton($lang->tree->syncFromProduct, 'id=copyModule onclick=syncModule('.$currentProduct.')'); + } + echo '
              '; + } + $maxOrder = 0; + echo '
              '; + foreach($sons as $sonModule) + { + if($sonModule->order > $maxOrder) $maxOrder = $sonModule->order; + echo '' . html::input("modules[id$sonModule->id]", $sonModule->name, 'class=text-3 style="margin-bottom:5px"') . '
              '; + } + for($i = 0; $i < TREE::NEW_CHILD_COUNT ; $i ++) echo '' . html::input("modules[]", '', 'class=text-3 style="margin-bottom:5px"') . '
              '; + ?> +
              +
              + + +
              +
              +
              + diff --git a/module/tree/view/edit.html.php b/module/tree/view/edit.html.php index 43d7bb1fd7..fa80c49559 100644 --- a/module/tree/view/edit.html.php +++ b/module/tree/view/edit.html.php @@ -1,38 +1,38 @@ - - * @package tree - * @version $Id$ - * @link http://www.zentao.net - */ -?> - -
              - - - - - - - - - - - type == 'bug'):?> - - - - - - - - -
              tree->edit;?>
              tree->parent;?>parent, "class='select-1'");?>
              tree->name;?>name, "class='text-1'");?>
              tree->owner;?>owner, "class='select-1'");?>
              - -
              -
              - + + * @package tree + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
              + + + + + + + + + + + type == 'bug'):?> + + + + + + + + +
              tree->edit;?>
              tree->parent;?>parent, "class='select-1'");?>
              tree->name;?>name, "class='text-1'");?>
              tree->owner;?>owner, "class='select-1'");?>
              + +
              +
              + diff --git a/module/upgrade/control.php b/module/upgrade/control.php index e0e8797e60..c3bbf2930a 100644 --- a/module/upgrade/control.php +++ b/module/upgrade/control.php @@ -1,81 +1,81 @@ - - * @package upgrade - * @version $Id$ - * @link http://www.zentao.net - */ -class upgrade extends control -{ - /** - * The index page. - * - * @access public - * @return void - */ - public function index() - { - $this->display(); - } - - /** - * Select the version of old zentao. - * - * @access public - * @return void - */ - public function selectVersion() - { - $version = str_replace(array(' ', '.'), array('', '_'), $this->config->installedVersion); - $version = strtolower($version); - $this->view->header->title = $this->lang->upgrade->common . $this->lang->colon . $this->lang->upgrade->selectVersion; - $this->view->position[] = $this->lang->upgrade->common; - $this->view->version = $version; - $this->display(); - } - - /** - * Confirm the version. - * - * @access public - * @return void - */ - public function confirm() - { - $this->view->header->title = $this->lang->upgrade->confirm; - $this->view->position[] = $this->lang->upgrade->common; - $this->view->confirm = $this->upgrade->getConfirm($this->post->fromVersion); - $this->view->fromVersion = $this->post->fromVersion; - - $this->display(); - } - - /** - * Execute the upgrading. - * - * @access public - * @return void - */ - public function execute() - { - $this->upgrade->execute($this->post->fromVersion); - - $this->view->header->title = $this->lang->upgrade->result; - $this->view->position[] = $this->lang->upgrade->common; - - if(!$this->upgrade->isError()) - { - $this->view->result = 'success'; - } - else - { - $this->view->result = 'fail'; - $this->view->errors = $this->upgrade->getError(); - } - $this->display(); - } -} + + * @package upgrade + * @version $Id$ + * @link http://www.zentao.net + */ +class upgrade extends control +{ + /** + * The index page. + * + * @access public + * @return void + */ + public function index() + { + $this->display(); + } + + /** + * Select the version of old zentao. + * + * @access public + * @return void + */ + public function selectVersion() + { + $version = str_replace(array(' ', '.'), array('', '_'), $this->config->installedVersion); + $version = strtolower($version); + $this->view->header->title = $this->lang->upgrade->common . $this->lang->colon . $this->lang->upgrade->selectVersion; + $this->view->position[] = $this->lang->upgrade->common; + $this->view->version = $version; + $this->display(); + } + + /** + * Confirm the version. + * + * @access public + * @return void + */ + public function confirm() + { + $this->view->header->title = $this->lang->upgrade->confirm; + $this->view->position[] = $this->lang->upgrade->common; + $this->view->confirm = $this->upgrade->getConfirm($this->post->fromVersion); + $this->view->fromVersion = $this->post->fromVersion; + + $this->display(); + } + + /** + * Execute the upgrading. + * + * @access public + * @return void + */ + public function execute() + { + $this->upgrade->execute($this->post->fromVersion); + + $this->view->header->title = $this->lang->upgrade->result; + $this->view->position[] = $this->lang->upgrade->common; + + if(!$this->upgrade->isError()) + { + $this->view->result = 'success'; + } + else + { + $this->view->result = 'fail'; + $this->view->errors = $this->upgrade->getError(); + } + $this->display(); + } +} diff --git a/module/upgrade/lang/en.php b/module/upgrade/lang/en.php index 56fd63c99f..09c41dfe9e 100644 --- a/module/upgrade/lang/en.php +++ b/module/upgrade/lang/en.php @@ -1,61 +1,61 @@ - - * @package upgrade - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->upgrade->common = 'Upgrade'; -$lang->upgrade->result = 'Result'; -$lang->upgrade->fail = 'Fail'; -$lang->upgrade->success = 'Success'; -$lang->upgrade->tohome = 'Go to index'; -$lang->upgrade->warnning= 'Warning'; -$lang->upgrade->warnningContent = << -EOT; - - - - - - -$lang->upgrade->setStatusFile = "

              For security reason, we will check file %s
              - But this file doesn't exist or out of date. You can use the flowing command to create(update)it
              - For linux:touch %s;
              - For windows:echo ok > %s

              - I have done this work, continue upgrade"; - - - -$lang->upgrade->selectVersion = 'Select version'; -$lang->upgrade->noteVersion = "Must select the correct version"; -$lang->upgrade->fromVersion = 'From version'; -$lang->upgrade->toVersion = 'To version'; -$lang->upgrade->confirm = 'Confirm the sql to executed.'; -$lang->upgrade->sureExecute = 'Execute'; - -$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; -$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; -$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; -$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; -$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; -$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; -$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; -$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; -$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; -$lang->upgrade->fromVersions['1_1'] = '1.1'; -$lang->upgrade->fromVersions['1_2'] = '1.2'; -$lang->upgrade->fromVersions['1_3'] = '1.3'; -$lang->upgrade->fromVersions['1_4'] = '1.4'; -$lang->upgrade->fromVersions['1_5'] = '1.5'; -$lang->upgrade->fromVersions['2_0'] = '2.0'; -$lang->upgrade->fromVersions['2_1'] = '2.1'; -$lang->upgrade->fromVersions['2_2'] = '2.2'; -$lang->upgrade->fromVersions['2_3'] = '2.3'; -$lang->upgrade->fromVersions['2_4'] = '2.4'; -$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; + + * @package upgrade + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->upgrade->common = 'Upgrade'; +$lang->upgrade->result = 'Result'; +$lang->upgrade->fail = 'Fail'; +$lang->upgrade->success = 'Success'; +$lang->upgrade->tohome = 'Go to index'; +$lang->upgrade->warnning= 'Warning'; +$lang->upgrade->warnningContent = << +EOT; + + + + + + +$lang->upgrade->setStatusFile = "

              For security reason, we will check file %s
              + But this file doesn't exist or out of date. You can use the flowing command to create(update)it
              + For linux:touch %s;
              + For windows:echo ok > %s

              + I have done this work, continue upgrade"; + + + +$lang->upgrade->selectVersion = 'Select version'; +$lang->upgrade->noteVersion = "Must select the correct version"; +$lang->upgrade->fromVersion = 'From version'; +$lang->upgrade->toVersion = 'To version'; +$lang->upgrade->confirm = 'Confirm the sql to executed.'; +$lang->upgrade->sureExecute = 'Execute'; + +$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; +$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; +$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; +$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; +$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; +$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; +$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; +$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; +$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; +$lang->upgrade->fromVersions['1_1'] = '1.1'; +$lang->upgrade->fromVersions['1_2'] = '1.2'; +$lang->upgrade->fromVersions['1_3'] = '1.3'; +$lang->upgrade->fromVersions['1_4'] = '1.4'; +$lang->upgrade->fromVersions['1_5'] = '1.5'; +$lang->upgrade->fromVersions['2_0'] = '2.0'; +$lang->upgrade->fromVersions['2_1'] = '2.1'; +$lang->upgrade->fromVersions['2_2'] = '2.2'; +$lang->upgrade->fromVersions['2_3'] = '2.3'; +$lang->upgrade->fromVersions['2_4'] = '2.4'; +$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; diff --git a/module/upgrade/lang/zh-cn.php b/module/upgrade/lang/zh-cn.php index 512b681a6d..e55fa13ccd 100644 --- a/module/upgrade/lang/zh-cn.php +++ b/module/upgrade/lang/zh-cn.php @@ -1,61 +1,61 @@ - - * @package upgrade - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->upgrade->common = '升级'; -$lang->upgrade->result = '升级结果'; -$lang->upgrade->fail = '升级失败'; -$lang->upgrade->success = '升级成功'; -$lang->upgrade->tohome = '返回首页'; -$lang->upgrade->warnning= '警告'; -$lang->upgrade->warnningContent = << -备份方法:
              -1. 可以通过phpMyAdmin进行备份。
              -2. 使用mysql命令行的工具。
              - # mysqldump -u username -p dbname > filename
              - 要将上面红色的部分分别替换成对应的用户名和禅道系统的数据库名。
              - 比如: mysqldump -u root -p zentao >zentao.bak -EOT; -$lang->upgrade->setStatusFile = '

              基于安全考虑,升级程序会检查%s文件的最后更新时间, 以确保安全!

              - 该文件不存在或者已经过期,请用下面的命令来创建或者更新它。 -
                -
              • linux下面的命令:touch %s;
              • -
              • windows打开命令行,执行echo ok > %s
              • -
              • 或者删掉原来的ok文件,重新创建一个ok文件,不需要扩展名,不需要内容。
              • -
              - 我已经仔细阅读上面提示且完成上述工作,继续更新'; -$lang->upgrade->selectVersion = '选择版本'; -$lang->upgrade->noteVersion = "务必选择正确的版本,否则会造成数据丢失。"; -$lang->upgrade->fromVersion = '原来的版本'; -$lang->upgrade->toVersion = '升级到'; -$lang->upgrade->confirm = '确认要执行的SQL语句'; -$lang->upgrade->sureExecute = '确认执行'; - -$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; -$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; -$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; -$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; -$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; -$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; -$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; -$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; -$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; -$lang->upgrade->fromVersions['1_1'] = '1.1'; -$lang->upgrade->fromVersions['1_2'] = '1.2'; -$lang->upgrade->fromVersions['1_3'] = '1.3'; -$lang->upgrade->fromVersions['1_4'] = '1.4'; -$lang->upgrade->fromVersions['1_5'] = '1.5'; -$lang->upgrade->fromVersions['2_0'] = '2.0'; -$lang->upgrade->fromVersions['2_1'] = '2.1'; -$lang->upgrade->fromVersions['2_2'] = '2.2'; -$lang->upgrade->fromVersions['2_3'] = '2.3'; -$lang->upgrade->fromVersions['2_4'] = '2.4'; -$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; + + * @package upgrade + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->upgrade->common = '升级'; +$lang->upgrade->result = '升级结果'; +$lang->upgrade->fail = '升级失败'; +$lang->upgrade->success = '升级成功'; +$lang->upgrade->tohome = '返回首页'; +$lang->upgrade->warnning= '警告'; +$lang->upgrade->warnningContent = << +备份方法:
              +1. 可以通过phpMyAdmin进行备份。
              +2. 使用mysql命令行的工具。
              + # mysqldump -u username -p dbname > filename
              + 要将上面红色的部分分别替换成对应的用户名和禅道系统的数据库名。
              + 比如: mysqldump -u root -p zentao >zentao.bak +EOT; +$lang->upgrade->setStatusFile = '

              基于安全考虑,升级程序会检查%s文件的最后更新时间, 以确保安全!

              + 该文件不存在或者已经过期,请用下面的命令来创建或者更新它。 +
                +
              • linux下面的命令:touch %s;
              • +
              • windows打开命令行,执行echo ok > %s
              • +
              • 或者删掉原来的ok文件,重新创建一个ok文件,不需要扩展名,不需要内容。
              • +
              + 我已经仔细阅读上面提示且完成上述工作,继续更新'; +$lang->upgrade->selectVersion = '选择版本'; +$lang->upgrade->noteVersion = "务必选择正确的版本,否则会造成数据丢失。"; +$lang->upgrade->fromVersion = '原来的版本'; +$lang->upgrade->toVersion = '升级到'; +$lang->upgrade->confirm = '确认要执行的SQL语句'; +$lang->upgrade->sureExecute = '确认执行'; + +$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; +$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; +$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; +$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; +$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; +$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; +$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; +$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; +$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; +$lang->upgrade->fromVersions['1_1'] = '1.1'; +$lang->upgrade->fromVersions['1_2'] = '1.2'; +$lang->upgrade->fromVersions['1_3'] = '1.3'; +$lang->upgrade->fromVersions['1_4'] = '1.4'; +$lang->upgrade->fromVersions['1_5'] = '1.5'; +$lang->upgrade->fromVersions['2_0'] = '2.0'; +$lang->upgrade->fromVersions['2_1'] = '2.1'; +$lang->upgrade->fromVersions['2_2'] = '2.2'; +$lang->upgrade->fromVersions['2_3'] = '2.3'; +$lang->upgrade->fromVersions['2_4'] = '2.4'; +$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; diff --git a/module/upgrade/lang/zh-tw.php b/module/upgrade/lang/zh-tw.php index 852c99f311..7506c68bf5 100644 --- a/module/upgrade/lang/zh-tw.php +++ b/module/upgrade/lang/zh-tw.php @@ -1,61 +1,61 @@ - - * @package upgrade - * @version $Id: zh-tw.php 2583 2012-02-17 07:25:56Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->upgrade->common = '升級'; -$lang->upgrade->result = '升級結果'; -$lang->upgrade->fail = '升級失敗'; -$lang->upgrade->success = '升級成功'; -$lang->upgrade->tohome = '返迴首頁'; -$lang->upgrade->warnning= '警告'; -$lang->upgrade->warnningContent = << -備份方法:
              -1. 可以通過phpMyAdmin進行備份。
              -2. 使用mysql命令行的工具。
              - # mysqldump -u username -p dbname > filename
              - 要將上面紅色的部分分別替換成對應的用戶名和禪道系統的資料庫名。
              - 比如: mysqldump -u root -p zentao >zentao.bak -EOT; -$lang->upgrade->setStatusFile = '

              基于安全考慮,升級程序會檢查%s檔案的最後更新時間, 以確保安全!

              - 該檔案不存在或者已經過期,請用下面的命令來創建或者更新它。 -
                -
              • linux下面的命令:touch %s;
              • -
              • windows打開命令行,執行echo ok > %s
              • -
              • 或者刪掉原來的ok檔案,重新創建一個ok檔案,不需要副檔名,不需要內容。
              • -
              - 我已經仔細閲讀上面提示且完成上述工作,繼續更新'; -$lang->upgrade->selectVersion = '選擇版本'; -$lang->upgrade->noteVersion = "務必選擇正確的版本,否則會造成數據丟失。"; -$lang->upgrade->fromVersion = '原來的版本'; -$lang->upgrade->toVersion = '升級到'; -$lang->upgrade->confirm = '確認要執行的SQL語句'; -$lang->upgrade->sureExecute = '確認執行'; - -$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; -$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; -$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; -$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; -$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; -$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; -$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; -$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; -$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; -$lang->upgrade->fromVersions['1_1'] = '1.1'; -$lang->upgrade->fromVersions['1_2'] = '1.2'; -$lang->upgrade->fromVersions['1_3'] = '1.3'; -$lang->upgrade->fromVersions['1_4'] = '1.4'; -$lang->upgrade->fromVersions['1_5'] = '1.5'; -$lang->upgrade->fromVersions['2_0'] = '2.0'; -$lang->upgrade->fromVersions['2_1'] = '2.1'; -$lang->upgrade->fromVersions['2_2'] = '2.2'; -$lang->upgrade->fromVersions['2_3'] = '2.3'; -$lang->upgrade->fromVersions['2_4'] = '2.4'; -$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; + + * @package upgrade + * @version $Id: zh-tw.php 2583 2012-02-17 07:25:56Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->upgrade->common = '升級'; +$lang->upgrade->result = '升級結果'; +$lang->upgrade->fail = '升級失敗'; +$lang->upgrade->success = '升級成功'; +$lang->upgrade->tohome = '返迴首頁'; +$lang->upgrade->warnning= '警告'; +$lang->upgrade->warnningContent = << +備份方法:
              +1. 可以通過phpMyAdmin進行備份。
              +2. 使用mysql命令行的工具。
              + # mysqldump -u username -p dbname > filename
              + 要將上面紅色的部分分別替換成對應的用戶名和禪道系統的資料庫名。
              + 比如: mysqldump -u root -p zentao >zentao.bak +EOT; +$lang->upgrade->setStatusFile = '

              基于安全考慮,升級程序會檢查%s檔案的最後更新時間, 以確保安全!

              + 該檔案不存在或者已經過期,請用下面的命令來創建或者更新它。 +
                +
              • linux下面的命令:touch %s;
              • +
              • windows打開命令行,執行echo ok > %s
              • +
              • 或者刪掉原來的ok檔案,重新創建一個ok檔案,不需要副檔名,不需要內容。
              • +
              + 我已經仔細閲讀上面提示且完成上述工作,繼續更新'; +$lang->upgrade->selectVersion = '選擇版本'; +$lang->upgrade->noteVersion = "務必選擇正確的版本,否則會造成數據丟失。"; +$lang->upgrade->fromVersion = '原來的版本'; +$lang->upgrade->toVersion = '升級到'; +$lang->upgrade->confirm = '確認要執行的SQL語句'; +$lang->upgrade->sureExecute = '確認執行'; + +$lang->upgrade->fromVersions['0_3beta'] = '0.3 BETA'; +$lang->upgrade->fromVersions['0_4beta'] = '0.4 BETA'; +$lang->upgrade->fromVersions['0_5beta'] = '0.5 BETA'; +$lang->upgrade->fromVersions['0_6beta'] = '0.6 BETA'; +$lang->upgrade->fromVersions['1_0beta'] = '1.0 BETA'; +$lang->upgrade->fromVersions['1_0rc1'] = '1.0 RC1'; +$lang->upgrade->fromVersions['1_0rc2'] = '1.0 RC2'; +$lang->upgrade->fromVersions['1_0'] = '1.0 STABLE'; +$lang->upgrade->fromVersions['1_0_1'] = '1.0.1'; +$lang->upgrade->fromVersions['1_1'] = '1.1'; +$lang->upgrade->fromVersions['1_2'] = '1.2'; +$lang->upgrade->fromVersions['1_3'] = '1.3'; +$lang->upgrade->fromVersions['1_4'] = '1.4'; +$lang->upgrade->fromVersions['1_5'] = '1.5'; +$lang->upgrade->fromVersions['2_0'] = '2.0'; +$lang->upgrade->fromVersions['2_1'] = '2.1'; +$lang->upgrade->fromVersions['2_2'] = '2.2'; +$lang->upgrade->fromVersions['2_3'] = '2.3'; +$lang->upgrade->fromVersions['2_4'] = '2.4'; +$lang->upgrade->fromVersions['3_0_beta1'] = '3.0.beta1'; diff --git a/module/upgrade/model.php b/module/upgrade/model.php index 6b2d330bac..1c7932f638 100644 --- a/module/upgrade/model.php +++ b/module/upgrade/model.php @@ -1,1207 +1,1207 @@ - - * @package upgrade - * @version $Id$ - * @link http://www.zentao.net - */ -?> -loadModel('setting'); - } - - /** - * The execute method. According to the $fromVersion call related methods. - * - * @param string $fromVersion - * @access public - * @return void - */ - public function execute($fromVersion) - { - if($fromVersion == '0_3beta') - { - $this->upgradeFrom0_3To0_4(); - $this->upgradeFrom0_4To0_5(); - $this->upgradeFrom0_5To0_6(); - $this->upgradeFrom0_6To1_0_B(); - $this->upgradeFrom1_0betaTo1_0rc1(); - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '0_4beta') - { - $this->upgradeFrom0_4To0_5(); - $this->upgradeFrom0_5To0_6(); - $this->upgradeFrom0_6To1_0_B(); - $this->upgradeFrom1_0betaTo1_0rc1(); - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '0_5beta') - { - $this->upgradeFrom0_5To0_6(); - $this->upgradeFrom0_6To1_0_B(); - $this->upgradeFrom1_0betaTo1_0rc1(); - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '0_6beta') - { - $this->upgradeFrom0_6To1_0_B(); - $this->upgradeFrom1_0betaTo1_0rc1(); - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_0beta') - { - $this->upgradeFrom1_0betaTo1_0rc1(); - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_0rc1') - { - $this->upgradeFrom1_0rc1To1_0rc2(); - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_0rc2') - { - $this->upgradeFrom1_0rc2To1_0stable(); - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_0') - { - $this->upgradeFrom1_0stableTo1_0_1(); - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_0_1') - { - $this->upgradeFrom1_0_1To1_1(); - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_1') - { - $this->upgradeFrom1_1To1_2(); - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_2') - { - $this->upgradeFrom1_2To1_3(); - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_3') - { - $this->upgradeFrom1_3To1_4(); - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_4') - { - $this->upgradeFrom1_4To1_5(); - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '1_5') - { - $this->upgradeFrom1_5To2_0(); - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '2_0') - { - $this->upgradeFrom2_0To2_1(); - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '2_1') - { - $this->upgradeFrom2_1To2_2(); - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '2_2') - { - $this->upgradeFrom2_2To2_3(); - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '2_3') - { - $this->upgradeFrom2_3To2_4(); - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '2_4') - { - $this->upgradeFrom2_4To3_0_beta1(); - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - elseif($fromVersion == '3_0_beta1') - { - $this->upgradeFrom3_0_beta1To3_0_beta2(); - } - - $this->deletePatch(); - $this->setting->setSN(); - } - - /** - * Create the confirm contents. - * - * @param string $fromVersion - * @access public - * @return string - */ - public function getConfirm($fromVersion) - { - $confirmContent = ''; - if($fromVersion == '0_3beta') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('0.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '0_4beta') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('0.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '0_5beta') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '0_6beta') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_0beta') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_0rc1') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_0rc2' || $fromVersion == '1_0' || $fromVersion == '1_0_1') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_1') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_2') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_3') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_4') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '1_5') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '2_0') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '2_1') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '2_2') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '2_3') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '2_4') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - elseif($fromVersion == '3_0_beta1') - { - $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); - } - - return str_replace('zt_', $this->config->db->prefix, $confirmContent); - } - - /** - * Upgrade from 0.3 to 0.4 - * - * @access public - * @return void - */ - public function upgradeFrom0_3To0_4() - { - $this->execSQL($this->getUpgradeFile('0.3')); - if(!$this->isError()) $this->setting->updateVersion('0.4 beta'); - } - - /** - * Upgrade from 0.4 to 0.5 - * - * @access public - * @return void - */ - public function upgradeFrom0_4To0_5() - { - $this->execSQL($this->getUpgradeFile('0.4')); - if(!$this->isError()) $this->setting->updateVersion('0.5 beta'); - } - - /** - * Upgrade from 0.5 to 0.6. - * - * @access public - * @return void - */ - public function upgradeFrom0_5To0_6() - { - $this->execSQL($this->getUpgradeFile('0.5')); - if(!$this->isError()) $this->setting->updateVersion('0.6 beta'); - } - - /** - * Upgrade from 0.6 to 1.0 beta. - * - * @access public - * @return void - */ - public function upgradeFrom0_6To1_0_B() - { - $this->execSQL($this->getUpgradeFile('0.6')); - if(!$this->isError()) $this->setting->updateVersion('1.0beta'); - } - - /** - * Upgrade from 1.0 beta to 1.0 rc1. - * - * @access public - * @return void - */ - public function upgradeFrom1_0betaTo1_0rc1() - { - $this->execSQL($this->getUpgradeFile('1.0.beta')); - $this->updateCompany(); - if(!$this->isError()) $this->setting->updateVersion('1.0rc1'); - } - - /** - * Upgrade from 1.0 rc1 to 1.0 rc2. - * - * @access public - * @return void - */ - public function upgradeFrom1_0rc1To1_0rc2() - { - $this->execSQL($this->getUpgradeFile('1.0.rc1')); - if(!$this->isError()) $this->setting->updateVersion('1.0rc2'); - } - - /** - * Upgrade from 1.0 rc2 to 1.0 stable. - * - * @access public - * @return void - */ - public function upgradeFrom1_0rc2To1_0stable() - { - $this->setting->updateVersion('1.0'); - } - - /** - * Upgrade from 1.0 stable to 1.0.1. - * - * @access public - * @return void - */ - public function upgradeFrom1_0stableTo1_0_1() - { - $this->setting->updateVersion('1.0.1'); - } - - /** - * Upgrade from 1.0.1 to 1.1. - * - * @access public - * @return void - */ - public function upgradeFrom1_0_1To1_1() - { - $this->execSQL($this->getUpgradeFile('1.0.1')); - if(!$this->isError()) $this->setting->updateVersion('1.1'); - } - - /** - * Upgrade from 1.1 to 1.2. - * - * @access public - * @return void - */ - public function upgradeFrom1_1To1_2() - { - $this->execSQL($this->getUpgradeFile('1.1')); - if(!$this->isError()) $this->setting->updateVersion('1.2'); - } - - /** - * Upgrade from 1.2 to 1.3. - * - * @access public - * @return void - */ - public function upgradeFrom1_2To1_3() - { - $this->execSQL($this->getUpgradeFile('1.2')); - $this->updateUBB(); - $this->updateNL1_2(); - if(!$this->isError()) $this->setting->updateVersion('1.3'); - } - - /** - * Upgrade from 1.3 to 1.4. - * - * @access public - * @return void - */ - public function upgradeFrom1_3To1_4() - { - $this->execSQL($this->getUpgradeFile('1.3')); - $this->updateNL1_3(); - $this->updateTasks(); - if(!$this->isError()) $this->setting->updateVersion('1.4'); - } - - /** - * Upgrade from 1.4 to 1.5. - * - * @access public - * @return void - */ - public function upgradeFrom1_4To1_5() - { - $this->execSQL($this->getUpgradeFile('1.4')); - if(!$this->isError()) $this->setting->updateVersion('1.5'); - } - - /** - * Upgrade from 1.5 to 2.0. - * - * @access public - * @return void - */ - public function upgradeFrom1_5To2_0() - { - $this->execSQL($this->getUpgradeFile('1.5')); - if(!$this->isError()) $this->setting->updateVersion('2.0'); - } - - /** - * Upgrade from 2.0 to 2.1. - * - * @access public - * @return void - */ - public function upgradeFrom2_0To2_1() - { - $this->execSQL($this->getUpgradeFile('2.0')); - if(!$this->isError()) $this->setting->updateVersion('2.1'); - } - - /** - * Upgrade from 2.1 to 2.2. - * - * @access public - * @return void - */ - public function upgradeFrom2_1To2_2() - { - $this->execSQL($this->getUpgradeFile('2.1')); - if(!$this->isError()) $this->setting->updateVersion('2.2'); - } - - /** - * Upgrade from 2.2 to 2.3. - * - * @access public - * @return void - */ - public function upgradeFrom2_2To2_3() - { - $this->execSQL($this->getUpgradeFile('2.2')); - $this->updateCases(); - $this->updateActivatedCountOfBug(); - if(!$this->isError()) $this->setting->updateVersion('2.3'); - } - - /** - * Upgrade from 2.3 to 2.4. - * - * @access public - * @return void - */ - public function upgradeFrom2_3To2_4() - { - $this->execSQL($this->getUpgradeFile('2.3')); - if(!$this->isError()) $this->setting->updateVersion('2.4'); - } - - /** - * Upgrade from 2.4 to 3.0.beta1. - * - * @access public - * @return void - */ - public function upgradeFrom2_4To3_0_beta1() - { - $this->execSQL($this->getUpgradeFile('2.4')); - if(!$this->isError()) $this->setting->updateVersion('3.0.beta1'); - } - - /** - * Upgrade from 3_0_beta1To3_0 - * - * @access public - * @return void - */ - public function upgradeFrom3_0_beta1To3_0_beta2() - { - $this->execSQL($this->getUpgradeFile('3.0.beta1')); - $this->updateTableAction(); - $this->setOrderData(); - if(!$this->isError()) $this->setting->updateVersion('3.0.beta2'); - } - - /** - * Update company field. - * - * This method is used to update since 1.0 beta. Any new tables added after 1.0 beta should skip. - * - * @access public - * @return void - */ - public function updateCompany() - { - /* Get user defined constants. */ - $constants = get_defined_constants(true); - $userConstants = $constants['user']; - - /* Update tables. */ - foreach($userConstants as $key => $value) - { - if(strpos($key, 'TABLE') === false) continue; - if($key == 'TABLE_COMPANY') continue; - - $table = $value; - $result = $this->dbh->query("SHOW TABLES LIKE '$table'"); - if($result->rowCount() > 0) - { - $this->dbh->query("UPDATE $table SET company = '{$this->app->company->id}'"); - } - } - } - - /** - * Update ubb code in bug table and user Templates table to html. - * - * @access public - * @return void - */ - public function updateUBB() - { - $this->app->loadClass('ubb', true); - - $bugs = $this->dao->select('id, steps')->from(TABLE_BUG)->fetchAll(); - $userTemplates = $this->dao->select('id, content')->from(TABLE_USERTPL)->fetchAll(); - - foreach($bugs as $id => $bug) - { - $bug->steps = ubb::parseUBB($bug->steps); - $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bug->id)->exec(); - } - foreach($userTemplates as $template) - { - $template->content = ubb::parseUBB($template->content); - $this->dao->update(TABLE_USERTPL)->data($template)->where('id')->eq($template->id)->exec(); - } - } - - /** - * Update nl to br from 1.2 version. - * - * @access public - * @return void - */ - public function updateNL1_2() - { - $tasks = $this->dao->select('id, `desc`')->from(TABLE_TASK)->fetchAll(); - $stories = $this->dao->select('story, version, spec')->from(TABLE_STORYSPEC)->fetchAll(); - $todos = $this->dao->select('id, `desc`')->from(TABLE_TODO)->fetchAll(); - $testTasks = $this->dao->select('id, `desc`')->from(TABLE_TESTTASK)->fetchAll(); - - foreach($tasks as $task) - { - $task->desc = nl2br($task->desc); - $this->dao->update(TABLE_TASK)->data($task)->where('id')->eq($task->id)->exec(); - } - foreach($stories as $story) - { - $story->spec = nl2br($story->spec); - $this->dao->update(TABLE_STORYSPEC)->data($story)->where('story')->eq($story->story)->andWhere('version')->eq($story->version)->exec(); - } - - foreach($todos as $todo) - { - $todo->desc = nl2br($todo->desc); - $this->dao->update(TABLE_TODO)->data($todo)->where('id')->eq($todo->id)->exec(); - } - - foreach($testTasks as $testtask) - { - $testtask->desc = nl2br($testtask->desc); - $this->dao->update(TABLE_TESTTASK)->data($testtask)->where('id')->eq($testtask->id)->exec(); - } - } - - /** - * Update nl to br from 1.3 version. - * - * @access public - * @return void - */ - public function updateNL1_3() - { - $products = $this->dao->select('id, `desc`')->from(TABLE_PRODUCT)->fetchAll(); - $plans = $this->dao->select('id, `desc`')->from(TABLE_PRODUCTPLAN)->fetchAll(); - $releases = $this->dao->select('id, `desc`')->from(TABLE_RELEASE)->fetchAll(); - $projects = $this->dao->select('id, `desc`, goal')->from(TABLE_PROJECT)->fetchAll(); - $builds = $this->dao->select('id, `desc`')->from(TABLE_BUILD)->fetchAll(); - - foreach($products as $product) - { - $product->desc = nl2br($product->desc); - $this->dao->update(TABLE_PRODUCT)->data($product)->where('id')->eq($product->id)->exec(); - } - - foreach($plans as $plan) - { - $plan->desc = nl2br($plan->desc); - $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->where('id')->eq($plan->id)->exec(); - } - - foreach($releases as $release) - { - $release->desc = nl2br($release->desc); - $this->dao->update(TABLE_RELEASE)->data($release)->where('id')->eq($release->id)->exec(); - } - - foreach($projects as $project) - { - $project->desc = nl2br($project->desc); - $project->goal = nl2br($project->goal); - $this->dao->update(TABLE_PROJECT)->data($project)->where('id')->eq($project->id)->exec(); - } - - foreach($builds as $build) - { - $build->desc = nl2br($build->desc); - $this->dao->update(TABLE_BUILD)->data($build)->where('id')->eq($build->id)->exec(); - } - } - - /** - * Update task fields. - * - * @access public - * @return void - */ - public function updateTasks() - { - /* Get all actions of tasks. */ - $actions = $this->dao->select('*')->from(TABLE_ACTION) - ->where('objectType')->eq('task') - ->orderBy('id') - ->fetchAll('id'); - - /* Get histories about status field. */ - $histories = $this->dao->select()->from(TABLE_HISTORY) - ->where('action')->in(array_keys($actions)) - ->andWhere('field')->eq('status') - ->orderBy('id') - ->fetchGroup('action'); - - $tasks = array(); - foreach($actions as $action) - { - if(!isset($tasks[$action->objectID])) - { - $tasks[$action->objectID] = new stdclass; - } - $task = $tasks[$action->objectID]; - - $task->id = $action->objectID; - $actionType = strtolower($action->action); - - /* Set the openedBy info. */ - if($actionType == 'opened') - { - $task->openedBy = $action->actor; - $task->openedDate = $action->date; - } - else - { - if(!isset($histories[$action->id])) continue; - - $actionHistories = $histories[$action->id]; - foreach($actionHistories as $history) - { - /* Finished by. */ - if($history->new == 'done') - { - $task->finishedBy = $action->actor; - $task->finishedDate = $action->date; - $action->action = 'finished'; - } - /* Canceled By. */ - elseif($history->new == 'cancel') - { - $task->canceledBy = $action->actor; - $task->canceledDate = $action->date; - $action->action = 'canceled'; - } - } - - /* Last edited by .*/ - $task->lastEditedBy = $action->actor; - $task->lastEditedDate = $action->date; - - /* Update action type. */ - $this->dao->update(TABLE_ACTION)->set('action')->eq($action->action)->where('id')->eq($action->id)->exec(false); - } - } - - /* Update db. */ - foreach($tasks as $task) - { - $this->dao->update(TABLE_TASK)->data($task, false)->where('id')->eq($task->id)->exec(false); - } - - $this->dao->update(TABLE_TASK)->set('assignedTo=openedBy, assignedDate = finishedDate')->where('status')->eq('done')->exec(false); - $this->dao->update(TABLE_TASK)->set('assignedTo=openedBy, assignedDate = canceledDate')->where('status')->eq('cancel')->exec(false); - - /* Update action name. */ - } - - /** - * Update activated count of Bug. - * - * @access public - * @return void - */ - public function updateActivatedCountOfBug() - { - $bugActivatedActions = $this->dao->select('*')->from(TABLE_ACTION)->where('action')->eq('activated')->andWhere('objectType')->eq('bug')->fetchAll(); - if(!empty($bugActivatedActions)) - { - foreach($bugActivatedActions as $action) - { - if(!isset($counts[$action->objectID])) $counts[$action->objectID] = 0; - $counts[$action->objectID] ++; - } - foreach($counts as $key => $count) - { - $this->dao->update(TABLE_BUG)->set('activatedCount')->eq($count)->where('id')->eq($key)->exec(); - } - } - } - - /** - * Update lastRun and lastResult field in zt_case - * - * @access public - * @return void - */ - public function updateCases() - { - $results = $this->dao->select('`case`, date, caseResult')->from(TABLE_TESTRESULT)->orderBy('id desc')->fetchGroup('case'); - foreach($results as $result) - { - $this->dao->update(TABLE_CASE) - ->set('lastRun')->eq($result[0]->date) - ->set('lastResult')->eq($result[0]->caseResult) - ->where('id')->eq($result[0]->case) - ->exec(); - } - } - - /** - * Update the data of action. - * - * @access public - * @return void - */ - public function updateTableAction() - { - $projectActions = $this->dao->select('objectID')->from(TABLE_ACTION)->where('objectType')->eq('project')->fetchPairs('objectID'); - $taskActions = $this->dao->select('objectID,project')->from(TABLE_ACTION)->where('objectType')->eq('task')->fetchPairs('objectID'); - - foreach($projectActions as $key => $projectID) - { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); - $productList = join(',', array_keys($products)); - $this->dao->update(TABLE_ACTION)->set('product')->eq($productList)->where('objectType')->eq('project')->andWhere('objectID')->eq($projectID)->exec(); - } - - foreach($taskActions as $taskID => $projectID) - { - $task = $this->dao->select('id,story')->from(TABLE_TASK)->where('id')->eq($taskID)->fetchPairs('id'); - if($task[$taskID] != 0) - { - $product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($task[$taskID])->fetchPairs('product'); - $productList = join(',', array_keys($product)); - } - else - { - $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); - $productList = join(',', array_keys($products)); - } - $this->dao->update(TABLE_ACTION)->set('product')->eq($productList)->where('objectType')->eq('task')->andWhere('objectID')->eq($taskID)->andWhere('project')->eq($projectID)->exec(); - } - - $actions = $this->dao->select('id,product')->from(TABLE_ACTION)->fetchPairs('id'); - foreach($actions as $id => $product) - { - $product = ',' . $product . ','; - $this->dao->update(TABLE_ACTION)->set('product')->eq($product)->exec(); - } - } - - /** - * Init the data of product and project order field. - * - * @access public - * @return void - */ - public function setOrderData() - { - $products = $this->dao->select('*')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->orderBy('code')->fetchAll('id'); - foreach(array_keys($products) as $key => $productID) - { - $this->dao->update(TABLE_PRODUCT)->set('`order`')->eq(($key + 1) * 10)->where('id')->eq($productID)->exec(); - } - $projects = $this->dao->select('*')->from(TABLE_PROJECT)->where('iscat')->eq(0)->andWhere('deleted')->eq(0)->orderBy('status, id desc')->fetchAll('id'); - foreach(array_keys($projects) as $key => $projectID) - { - $this->dao->update(TABLE_PROJECT)->set('`order`')->eq(($key + 1) * 10)->where('id')->eq($projectID)->exec(); - } - } - - /** - * Delete the patch record. - * - * @access public - * @return void - */ - public function deletePatch() - { - $this->dao->delete()->from(TABLE_EXTENSION)->where('type')->eq('patch')->exec(false); - $this->dao->delete()->from(TABLE_EXTENSION)->where('code')->in('zentaopatch,patch')->exec(false); - } - - /** - * Get the upgrade sql file. - * - * @param string $version - * @access public - * @return string - */ - public function getUpgradeFile($version) - { - return $this->app->getAppRoot() . 'db' . $this->app->getPathFix() . 'update' . $version . '.sql'; - } - - /** - * Execute a sql. - * - * @param string $sqlFile - * @access public - * @return void - */ - public function execSQL($sqlFile) - { - $mysqlVersion = $this->loadModel('install')->getMysqlVersion(); - - /* Read the sql file to lines, remove the comment lines, then join theme by ';'. */ - $sqls = explode("\n", file_get_contents($sqlFile)); - foreach($sqls as $key => $line) - { - $line = trim($line); - $sqls[$key] = $line; - if(strpos($line, '--') !== false or empty($line)) unset($sqls[$key]); - } - $sqls = explode(';', join("\n", $sqls)); - - foreach($sqls as $sql) - { - $sql = trim($sql); - if(empty($sql)) continue; - - if($mysqlVersion <= 4.1) - { - $sql = str_replace('DEFAULT CHARSET=utf8', '', $sql); - $sql = str_replace('CHARACTER SET utf8 COLLATE utf8_general_ci', '', $sql); - } - - $sql = str_replace('zt_', $this->config->db->prefix, $sql); - try - { - $this->dbh->exec($sql); - } - catch (PDOException $e) - { - self::$errors[] = $e->getMessage() . "

              The sql is: $sql

              "; - } - } - } - - /** - * Judge any error occers. - * - * @access public - * @return bool - */ - public function isError() - { - return !empty(self::$errors); - } - - /** - * Get errors during the upgrading. - * - * @access public - * @return array - */ - public function getError() - { - $errors = self::$errors; - self::$errors = array(); - return $errors; - } -} + + * @package upgrade + * @version $Id$ + * @link http://www.zentao.net + */ +?> +loadModel('setting'); + } + + /** + * The execute method. According to the $fromVersion call related methods. + * + * @param string $fromVersion + * @access public + * @return void + */ + public function execute($fromVersion) + { + if($fromVersion == '0_3beta') + { + $this->upgradeFrom0_3To0_4(); + $this->upgradeFrom0_4To0_5(); + $this->upgradeFrom0_5To0_6(); + $this->upgradeFrom0_6To1_0_B(); + $this->upgradeFrom1_0betaTo1_0rc1(); + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '0_4beta') + { + $this->upgradeFrom0_4To0_5(); + $this->upgradeFrom0_5To0_6(); + $this->upgradeFrom0_6To1_0_B(); + $this->upgradeFrom1_0betaTo1_0rc1(); + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '0_5beta') + { + $this->upgradeFrom0_5To0_6(); + $this->upgradeFrom0_6To1_0_B(); + $this->upgradeFrom1_0betaTo1_0rc1(); + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '0_6beta') + { + $this->upgradeFrom0_6To1_0_B(); + $this->upgradeFrom1_0betaTo1_0rc1(); + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_0beta') + { + $this->upgradeFrom1_0betaTo1_0rc1(); + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_0rc1') + { + $this->upgradeFrom1_0rc1To1_0rc2(); + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_0rc2') + { + $this->upgradeFrom1_0rc2To1_0stable(); + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_0') + { + $this->upgradeFrom1_0stableTo1_0_1(); + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_0_1') + { + $this->upgradeFrom1_0_1To1_1(); + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_1') + { + $this->upgradeFrom1_1To1_2(); + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_2') + { + $this->upgradeFrom1_2To1_3(); + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_3') + { + $this->upgradeFrom1_3To1_4(); + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_4') + { + $this->upgradeFrom1_4To1_5(); + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '1_5') + { + $this->upgradeFrom1_5To2_0(); + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '2_0') + { + $this->upgradeFrom2_0To2_1(); + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '2_1') + { + $this->upgradeFrom2_1To2_2(); + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '2_2') + { + $this->upgradeFrom2_2To2_3(); + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '2_3') + { + $this->upgradeFrom2_3To2_4(); + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '2_4') + { + $this->upgradeFrom2_4To3_0_beta1(); + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + elseif($fromVersion == '3_0_beta1') + { + $this->upgradeFrom3_0_beta1To3_0_beta2(); + } + + $this->deletePatch(); + $this->setting->setSN(); + } + + /** + * Create the confirm contents. + * + * @param string $fromVersion + * @access public + * @return string + */ + public function getConfirm($fromVersion) + { + $confirmContent = ''; + if($fromVersion == '0_3beta') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('0.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '0_4beta') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('0.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '0_5beta') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('0.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '0_6beta') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('0.6')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_0beta') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.beta')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_0rc1') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.rc1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_0rc2' || $fromVersion == '1_0' || $fromVersion == '1_0_1') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.0.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_1') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_2') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_3') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_4') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '1_5') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('1.5')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '2_0') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('2.0')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '2_1') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('2.1')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '2_2') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('2.2')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '2_3') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('2.3')); + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '2_4') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('2.4')); + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + elseif($fromVersion == '3_0_beta1') + { + $confirmContent .= file_get_contents($this->getUpgradeFile('3.0.beta1')); + } + + return str_replace('zt_', $this->config->db->prefix, $confirmContent); + } + + /** + * Upgrade from 0.3 to 0.4 + * + * @access public + * @return void + */ + public function upgradeFrom0_3To0_4() + { + $this->execSQL($this->getUpgradeFile('0.3')); + if(!$this->isError()) $this->setting->updateVersion('0.4 beta'); + } + + /** + * Upgrade from 0.4 to 0.5 + * + * @access public + * @return void + */ + public function upgradeFrom0_4To0_5() + { + $this->execSQL($this->getUpgradeFile('0.4')); + if(!$this->isError()) $this->setting->updateVersion('0.5 beta'); + } + + /** + * Upgrade from 0.5 to 0.6. + * + * @access public + * @return void + */ + public function upgradeFrom0_5To0_6() + { + $this->execSQL($this->getUpgradeFile('0.5')); + if(!$this->isError()) $this->setting->updateVersion('0.6 beta'); + } + + /** + * Upgrade from 0.6 to 1.0 beta. + * + * @access public + * @return void + */ + public function upgradeFrom0_6To1_0_B() + { + $this->execSQL($this->getUpgradeFile('0.6')); + if(!$this->isError()) $this->setting->updateVersion('1.0beta'); + } + + /** + * Upgrade from 1.0 beta to 1.0 rc1. + * + * @access public + * @return void + */ + public function upgradeFrom1_0betaTo1_0rc1() + { + $this->execSQL($this->getUpgradeFile('1.0.beta')); + $this->updateCompany(); + if(!$this->isError()) $this->setting->updateVersion('1.0rc1'); + } + + /** + * Upgrade from 1.0 rc1 to 1.0 rc2. + * + * @access public + * @return void + */ + public function upgradeFrom1_0rc1To1_0rc2() + { + $this->execSQL($this->getUpgradeFile('1.0.rc1')); + if(!$this->isError()) $this->setting->updateVersion('1.0rc2'); + } + + /** + * Upgrade from 1.0 rc2 to 1.0 stable. + * + * @access public + * @return void + */ + public function upgradeFrom1_0rc2To1_0stable() + { + $this->setting->updateVersion('1.0'); + } + + /** + * Upgrade from 1.0 stable to 1.0.1. + * + * @access public + * @return void + */ + public function upgradeFrom1_0stableTo1_0_1() + { + $this->setting->updateVersion('1.0.1'); + } + + /** + * Upgrade from 1.0.1 to 1.1. + * + * @access public + * @return void + */ + public function upgradeFrom1_0_1To1_1() + { + $this->execSQL($this->getUpgradeFile('1.0.1')); + if(!$this->isError()) $this->setting->updateVersion('1.1'); + } + + /** + * Upgrade from 1.1 to 1.2. + * + * @access public + * @return void + */ + public function upgradeFrom1_1To1_2() + { + $this->execSQL($this->getUpgradeFile('1.1')); + if(!$this->isError()) $this->setting->updateVersion('1.2'); + } + + /** + * Upgrade from 1.2 to 1.3. + * + * @access public + * @return void + */ + public function upgradeFrom1_2To1_3() + { + $this->execSQL($this->getUpgradeFile('1.2')); + $this->updateUBB(); + $this->updateNL1_2(); + if(!$this->isError()) $this->setting->updateVersion('1.3'); + } + + /** + * Upgrade from 1.3 to 1.4. + * + * @access public + * @return void + */ + public function upgradeFrom1_3To1_4() + { + $this->execSQL($this->getUpgradeFile('1.3')); + $this->updateNL1_3(); + $this->updateTasks(); + if(!$this->isError()) $this->setting->updateVersion('1.4'); + } + + /** + * Upgrade from 1.4 to 1.5. + * + * @access public + * @return void + */ + public function upgradeFrom1_4To1_5() + { + $this->execSQL($this->getUpgradeFile('1.4')); + if(!$this->isError()) $this->setting->updateVersion('1.5'); + } + + /** + * Upgrade from 1.5 to 2.0. + * + * @access public + * @return void + */ + public function upgradeFrom1_5To2_0() + { + $this->execSQL($this->getUpgradeFile('1.5')); + if(!$this->isError()) $this->setting->updateVersion('2.0'); + } + + /** + * Upgrade from 2.0 to 2.1. + * + * @access public + * @return void + */ + public function upgradeFrom2_0To2_1() + { + $this->execSQL($this->getUpgradeFile('2.0')); + if(!$this->isError()) $this->setting->updateVersion('2.1'); + } + + /** + * Upgrade from 2.1 to 2.2. + * + * @access public + * @return void + */ + public function upgradeFrom2_1To2_2() + { + $this->execSQL($this->getUpgradeFile('2.1')); + if(!$this->isError()) $this->setting->updateVersion('2.2'); + } + + /** + * Upgrade from 2.2 to 2.3. + * + * @access public + * @return void + */ + public function upgradeFrom2_2To2_3() + { + $this->execSQL($this->getUpgradeFile('2.2')); + $this->updateCases(); + $this->updateActivatedCountOfBug(); + if(!$this->isError()) $this->setting->updateVersion('2.3'); + } + + /** + * Upgrade from 2.3 to 2.4. + * + * @access public + * @return void + */ + public function upgradeFrom2_3To2_4() + { + $this->execSQL($this->getUpgradeFile('2.3')); + if(!$this->isError()) $this->setting->updateVersion('2.4'); + } + + /** + * Upgrade from 2.4 to 3.0.beta1. + * + * @access public + * @return void + */ + public function upgradeFrom2_4To3_0_beta1() + { + $this->execSQL($this->getUpgradeFile('2.4')); + if(!$this->isError()) $this->setting->updateVersion('3.0.beta1'); + } + + /** + * Upgrade from 3_0_beta1To3_0 + * + * @access public + * @return void + */ + public function upgradeFrom3_0_beta1To3_0_beta2() + { + $this->execSQL($this->getUpgradeFile('3.0.beta1')); + $this->updateTableAction(); + $this->setOrderData(); + if(!$this->isError()) $this->setting->updateVersion('3.0.beta2'); + } + + /** + * Update company field. + * + * This method is used to update since 1.0 beta. Any new tables added after 1.0 beta should skip. + * + * @access public + * @return void + */ + public function updateCompany() + { + /* Get user defined constants. */ + $constants = get_defined_constants(true); + $userConstants = $constants['user']; + + /* Update tables. */ + foreach($userConstants as $key => $value) + { + if(strpos($key, 'TABLE') === false) continue; + if($key == 'TABLE_COMPANY') continue; + + $table = $value; + $result = $this->dbh->query("SHOW TABLES LIKE '$table'"); + if($result->rowCount() > 0) + { + $this->dbh->query("UPDATE $table SET company = '{$this->app->company->id}'"); + } + } + } + + /** + * Update ubb code in bug table and user Templates table to html. + * + * @access public + * @return void + */ + public function updateUBB() + { + $this->app->loadClass('ubb', true); + + $bugs = $this->dao->select('id, steps')->from(TABLE_BUG)->fetchAll(); + $userTemplates = $this->dao->select('id, content')->from(TABLE_USERTPL)->fetchAll(); + + foreach($bugs as $id => $bug) + { + $bug->steps = ubb::parseUBB($bug->steps); + $this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bug->id)->exec(); + } + foreach($userTemplates as $template) + { + $template->content = ubb::parseUBB($template->content); + $this->dao->update(TABLE_USERTPL)->data($template)->where('id')->eq($template->id)->exec(); + } + } + + /** + * Update nl to br from 1.2 version. + * + * @access public + * @return void + */ + public function updateNL1_2() + { + $tasks = $this->dao->select('id, `desc`')->from(TABLE_TASK)->fetchAll(); + $stories = $this->dao->select('story, version, spec')->from(TABLE_STORYSPEC)->fetchAll(); + $todos = $this->dao->select('id, `desc`')->from(TABLE_TODO)->fetchAll(); + $testTasks = $this->dao->select('id, `desc`')->from(TABLE_TESTTASK)->fetchAll(); + + foreach($tasks as $task) + { + $task->desc = nl2br($task->desc); + $this->dao->update(TABLE_TASK)->data($task)->where('id')->eq($task->id)->exec(); + } + foreach($stories as $story) + { + $story->spec = nl2br($story->spec); + $this->dao->update(TABLE_STORYSPEC)->data($story)->where('story')->eq($story->story)->andWhere('version')->eq($story->version)->exec(); + } + + foreach($todos as $todo) + { + $todo->desc = nl2br($todo->desc); + $this->dao->update(TABLE_TODO)->data($todo)->where('id')->eq($todo->id)->exec(); + } + + foreach($testTasks as $testtask) + { + $testtask->desc = nl2br($testtask->desc); + $this->dao->update(TABLE_TESTTASK)->data($testtask)->where('id')->eq($testtask->id)->exec(); + } + } + + /** + * Update nl to br from 1.3 version. + * + * @access public + * @return void + */ + public function updateNL1_3() + { + $products = $this->dao->select('id, `desc`')->from(TABLE_PRODUCT)->fetchAll(); + $plans = $this->dao->select('id, `desc`')->from(TABLE_PRODUCTPLAN)->fetchAll(); + $releases = $this->dao->select('id, `desc`')->from(TABLE_RELEASE)->fetchAll(); + $projects = $this->dao->select('id, `desc`, goal')->from(TABLE_PROJECT)->fetchAll(); + $builds = $this->dao->select('id, `desc`')->from(TABLE_BUILD)->fetchAll(); + + foreach($products as $product) + { + $product->desc = nl2br($product->desc); + $this->dao->update(TABLE_PRODUCT)->data($product)->where('id')->eq($product->id)->exec(); + } + + foreach($plans as $plan) + { + $plan->desc = nl2br($plan->desc); + $this->dao->update(TABLE_PRODUCTPLAN)->data($plan)->where('id')->eq($plan->id)->exec(); + } + + foreach($releases as $release) + { + $release->desc = nl2br($release->desc); + $this->dao->update(TABLE_RELEASE)->data($release)->where('id')->eq($release->id)->exec(); + } + + foreach($projects as $project) + { + $project->desc = nl2br($project->desc); + $project->goal = nl2br($project->goal); + $this->dao->update(TABLE_PROJECT)->data($project)->where('id')->eq($project->id)->exec(); + } + + foreach($builds as $build) + { + $build->desc = nl2br($build->desc); + $this->dao->update(TABLE_BUILD)->data($build)->where('id')->eq($build->id)->exec(); + } + } + + /** + * Update task fields. + * + * @access public + * @return void + */ + public function updateTasks() + { + /* Get all actions of tasks. */ + $actions = $this->dao->select('*')->from(TABLE_ACTION) + ->where('objectType')->eq('task') + ->orderBy('id') + ->fetchAll('id'); + + /* Get histories about status field. */ + $histories = $this->dao->select()->from(TABLE_HISTORY) + ->where('action')->in(array_keys($actions)) + ->andWhere('field')->eq('status') + ->orderBy('id') + ->fetchGroup('action'); + + $tasks = array(); + foreach($actions as $action) + { + if(!isset($tasks[$action->objectID])) + { + $tasks[$action->objectID] = new stdclass; + } + $task = $tasks[$action->objectID]; + + $task->id = $action->objectID; + $actionType = strtolower($action->action); + + /* Set the openedBy info. */ + if($actionType == 'opened') + { + $task->openedBy = $action->actor; + $task->openedDate = $action->date; + } + else + { + if(!isset($histories[$action->id])) continue; + + $actionHistories = $histories[$action->id]; + foreach($actionHistories as $history) + { + /* Finished by. */ + if($history->new == 'done') + { + $task->finishedBy = $action->actor; + $task->finishedDate = $action->date; + $action->action = 'finished'; + } + /* Canceled By. */ + elseif($history->new == 'cancel') + { + $task->canceledBy = $action->actor; + $task->canceledDate = $action->date; + $action->action = 'canceled'; + } + } + + /* Last edited by .*/ + $task->lastEditedBy = $action->actor; + $task->lastEditedDate = $action->date; + + /* Update action type. */ + $this->dao->update(TABLE_ACTION)->set('action')->eq($action->action)->where('id')->eq($action->id)->exec(false); + } + } + + /* Update db. */ + foreach($tasks as $task) + { + $this->dao->update(TABLE_TASK)->data($task, false)->where('id')->eq($task->id)->exec(false); + } + + $this->dao->update(TABLE_TASK)->set('assignedTo=openedBy, assignedDate = finishedDate')->where('status')->eq('done')->exec(false); + $this->dao->update(TABLE_TASK)->set('assignedTo=openedBy, assignedDate = canceledDate')->where('status')->eq('cancel')->exec(false); + + /* Update action name. */ + } + + /** + * Update activated count of Bug. + * + * @access public + * @return void + */ + public function updateActivatedCountOfBug() + { + $bugActivatedActions = $this->dao->select('*')->from(TABLE_ACTION)->where('action')->eq('activated')->andWhere('objectType')->eq('bug')->fetchAll(); + if(!empty($bugActivatedActions)) + { + foreach($bugActivatedActions as $action) + { + if(!isset($counts[$action->objectID])) $counts[$action->objectID] = 0; + $counts[$action->objectID] ++; + } + foreach($counts as $key => $count) + { + $this->dao->update(TABLE_BUG)->set('activatedCount')->eq($count)->where('id')->eq($key)->exec(); + } + } + } + + /** + * Update lastRun and lastResult field in zt_case + * + * @access public + * @return void + */ + public function updateCases() + { + $results = $this->dao->select('`case`, date, caseResult')->from(TABLE_TESTRESULT)->orderBy('id desc')->fetchGroup('case'); + foreach($results as $result) + { + $this->dao->update(TABLE_CASE) + ->set('lastRun')->eq($result[0]->date) + ->set('lastResult')->eq($result[0]->caseResult) + ->where('id')->eq($result[0]->case) + ->exec(); + } + } + + /** + * Update the data of action. + * + * @access public + * @return void + */ + public function updateTableAction() + { + $projectActions = $this->dao->select('objectID')->from(TABLE_ACTION)->where('objectType')->eq('project')->fetchPairs('objectID'); + $taskActions = $this->dao->select('objectID,project')->from(TABLE_ACTION)->where('objectType')->eq('task')->fetchPairs('objectID'); + + foreach($projectActions as $key => $projectID) + { + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); + $productList = join(',', array_keys($products)); + $this->dao->update(TABLE_ACTION)->set('product')->eq($productList)->where('objectType')->eq('project')->andWhere('objectID')->eq($projectID)->exec(); + } + + foreach($taskActions as $taskID => $projectID) + { + $task = $this->dao->select('id,story')->from(TABLE_TASK)->where('id')->eq($taskID)->fetchPairs('id'); + if($task[$taskID] != 0) + { + $product = $this->dao->select('product')->from(TABLE_STORY)->where('id')->eq($task[$taskID])->fetchPairs('product'); + $productList = join(',', array_keys($product)); + } + else + { + $products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs('product'); + $productList = join(',', array_keys($products)); + } + $this->dao->update(TABLE_ACTION)->set('product')->eq($productList)->where('objectType')->eq('task')->andWhere('objectID')->eq($taskID)->andWhere('project')->eq($projectID)->exec(); + } + + $actions = $this->dao->select('id,product')->from(TABLE_ACTION)->fetchPairs('id'); + foreach($actions as $id => $product) + { + $product = ',' . $product . ','; + $this->dao->update(TABLE_ACTION)->set('product')->eq($product)->exec(); + } + } + + /** + * Init the data of product and project order field. + * + * @access public + * @return void + */ + public function setOrderData() + { + $products = $this->dao->select('*')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->orderBy('code')->fetchAll('id'); + foreach(array_keys($products) as $key => $productID) + { + $this->dao->update(TABLE_PRODUCT)->set('`order`')->eq(($key + 1) * 10)->where('id')->eq($productID)->exec(); + } + $projects = $this->dao->select('*')->from(TABLE_PROJECT)->where('iscat')->eq(0)->andWhere('deleted')->eq(0)->orderBy('status, id desc')->fetchAll('id'); + foreach(array_keys($projects) as $key => $projectID) + { + $this->dao->update(TABLE_PROJECT)->set('`order`')->eq(($key + 1) * 10)->where('id')->eq($projectID)->exec(); + } + } + + /** + * Delete the patch record. + * + * @access public + * @return void + */ + public function deletePatch() + { + $this->dao->delete()->from(TABLE_EXTENSION)->where('type')->eq('patch')->exec(false); + $this->dao->delete()->from(TABLE_EXTENSION)->where('code')->in('zentaopatch,patch')->exec(false); + } + + /** + * Get the upgrade sql file. + * + * @param string $version + * @access public + * @return string + */ + public function getUpgradeFile($version) + { + return $this->app->getAppRoot() . 'db' . $this->app->getPathFix() . 'update' . $version . '.sql'; + } + + /** + * Execute a sql. + * + * @param string $sqlFile + * @access public + * @return void + */ + public function execSQL($sqlFile) + { + $mysqlVersion = $this->loadModel('install')->getMysqlVersion(); + + /* Read the sql file to lines, remove the comment lines, then join theme by ';'. */ + $sqls = explode("\n", file_get_contents($sqlFile)); + foreach($sqls as $key => $line) + { + $line = trim($line); + $sqls[$key] = $line; + if(strpos($line, '--') !== false or empty($line)) unset($sqls[$key]); + } + $sqls = explode(';', join("\n", $sqls)); + + foreach($sqls as $sql) + { + $sql = trim($sql); + if(empty($sql)) continue; + + if($mysqlVersion <= 4.1) + { + $sql = str_replace('DEFAULT CHARSET=utf8', '', $sql); + $sql = str_replace('CHARACTER SET utf8 COLLATE utf8_general_ci', '', $sql); + } + + $sql = str_replace('zt_', $this->config->db->prefix, $sql); + try + { + $this->dbh->exec($sql); + } + catch (PDOException $e) + { + self::$errors[] = $e->getMessage() . "

              The sql is: $sql

              "; + } + } + } + + /** + * Judge any error occers. + * + * @access public + * @return bool + */ + public function isError() + { + return !empty(self::$errors); + } + + /** + * Get errors during the upgrading. + * + * @access public + * @return array + */ + public function getError() + { + $errors = self::$errors; + self::$errors = array(); + return $errors; + } +} diff --git a/module/upgrade/view/confirm.html.php b/module/upgrade/view/confirm.html.php index fc9d901350..d1928c3b04 100644 --- a/module/upgrade/view/confirm.html.php +++ b/module/upgrade/view/confirm.html.php @@ -1,26 +1,26 @@ - - * @package upgrade - * @version $Id$ - */ -?> - - -
              -
              '> - - - - - - - -
              upgrade->confirm;?>
              upgrade->sureExecute) . html::hidden('fromVersion', $fromVersion);?>
              -
              -
              - + + * @package upgrade + * @version $Id$ + */ +?> + + +
              +
              '> + + + + + + + +
              upgrade->confirm;?>
              upgrade->sureExecute) . html::hidden('fromVersion', $fromVersion);?>
              +
              +
              + diff --git a/module/upgrade/view/execute.html.php b/module/upgrade/view/execute.html.php index 432afa9da3..9f0c65312d 100644 --- a/module/upgrade/view/execute.html.php +++ b/module/upgrade/view/execute.html.php @@ -1,30 +1,30 @@ - - * @package upgrade - * @version $Id$ - */ -?> - - - - - - -
              upgrade->$result;?>
              - upgrade->tohome, 'index.php'); - } - ?> -
              - + + * @package upgrade + * @version $Id$ + */ +?> + + + + + + +
              upgrade->$result;?>
              + upgrade->tohome, 'index.php'); + } + ?> +
              + diff --git a/module/upgrade/view/index.html.php b/module/upgrade/view/index.html.php index 31f639a889..e1d1ab74d7 100644 --- a/module/upgrade/view/index.html.php +++ b/module/upgrade/view/index.html.php @@ -1,22 +1,22 @@ - - * @package upgrade - * @version $Id$ - */ -?> - - - - - - - - - -
              upgrade->warnning;?>
              upgrade->warnningContent;?>
              upgrade->common, inlink('selectVersion'));?>
              - + + * @package upgrade + * @version $Id$ + */ +?> + + + + + + + + + +
              upgrade->warnning;?>
              upgrade->warnningContent;?>
              upgrade->common, inlink('selectVersion'));?>
              + diff --git a/module/upgrade/view/selectversion.html.php b/module/upgrade/view/selectversion.html.php index 34e540201e..9a34aa4583 100644 --- a/module/upgrade/view/selectversion.html.php +++ b/module/upgrade/view/selectversion.html.php @@ -1,29 +1,29 @@ - - * @package upgrade - * @version $Id$ - */ -?> - -
              '> - - - - - - - - - - - - - -
              upgrade->selectVersion;?>
              upgrade->fromVersion;?>upgrade->fromVersions, $version) . "{$lang->upgrade->noteVersion}";?>
              upgrade->toVersion;?>version;?>
              upgrade->common);?>
              -
              - + + * @package upgrade + * @version $Id$ + */ +?> + +
              '> + + + + + + + + + + + + + +
              upgrade->selectVersion;?>
              upgrade->fromVersion;?>upgrade->fromVersions, $version) . "{$lang->upgrade->noteVersion}";?>
              upgrade->toVersion;?>version;?>
              upgrade->common);?>
              +
              + diff --git a/module/user/control.php b/module/user/control.php index 1b461ee338..ed97b144e4 100644 --- a/module/user/control.php +++ b/module/user/control.php @@ -1,506 +1,506 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -class user extends control -{ - private $referer; - - /** - * Construct - * - * @access public - * @return void - */ - public function __construct() - { - parent::__construct(); - $this->loadModel('company')->setMenu(); - $this->loadModel('dept'); - } - - /** - * View a user. - * - * @param string $account - * @access public - * @return void - */ - public function view($account) - { - $this->locate($this->createLink('user', 'profile', "account=$account")); - } - - /** - * Todos of a user. - * - * @param string $account - * @param string $type the tod type, today|lastweek|thisweek|all|undone, or a date. - * @param string $status - * @access public - * @return void - */ - public function todo($account, $type = 'today', $status = 'all') - { - /* Set thie url to session. */ - $uri = $this->app->getURI(true); - $this->session->set('todoList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('taskList', $uri); - - /* set menus. */ - $this->lang->set('menugroup.user', 'company'); - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - /* Get user, totos. */ - $user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); - $todos = $this->loadModel('todo')->getList($type, $account, $status); - $date = (int)$type == 0 ? $this->todo->today() : $type; - - $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->user->todo; - $position[] = $this->lang->user->todo; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->tabID = 'todo'; - $this->view->dates = $this->todo->buildDateList(); - $this->view->date = $date; - $this->view->todos = $todos; - $this->view->user = $user; - $this->view->account = $account; - $this->view->type = $type; - - $this->display(); - } - - /** - * Taskes of a user. - * - * @param string $account - * @access public - * @return void - */ - public function task($account) - { - /* Save the session. */ - $this->session->set('taskList', $this->app->getURI(true)); - - /* Set the menu. */ - $this->lang->set('menugroup.user', 'company'); - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - /* Assign. */ - $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->task; - $position[] = $this->lang->user->task; - $this->view->header = $header; - $this->view->position = $position; - $this->view->tabID = 'task'; - $this->view->tasks = $this->loadModel('task')->getUserTasks($account); - $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); - - $this->display(); - } - - /** - * User bugs. - * - * @param string $account - * @access public - * @return void - */ - public function bug($account) - { - /* Save the session. */ - $this->session->set('bugList', $this->app->getURI(true)); - - /* Set menu. */ - $this->lang->set('menugroup.user', 'company'); - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - /* Load the lang of bug module. */ - $this->app->loadLang('bug'); - - $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->bug; - $position[] = $this->lang->user->bug; - - $this->view->header = $header; - $this->view->position = $position; - $this->view->tabID = 'bug'; - $this->view->bugs = $this->user->getBugs($account); - $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); - $this->view->users = $this->user->getPairs('noletter'); - - $this->display(); - } - - /** - * User projects. - * - * @param string $account - * @access public - * @return void - */ - public function project($account) - { - /* Set the menus. */ - $this->loadModel('project'); - $this->lang->set('menugroup.user', 'company'); - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->project; - $position[] = $this->lang->user->project; - $this->view->header = $header; - $this->view->position = $position; - $this->view->tabID = 'project'; - $this->view->projects = $this->user->getProjects($account); - $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); - - $this->display(); - } - - /** - * The profile of a user. - * - * @param string $account - * @access public - * @return void - */ - public function profile($account) - { - $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->profile; - $position[] = $this->lang->user->profile; - - /* Set menu. */ - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - $user = $this->user->getById($account); - $deptPath = $this->dept->getParents($user->dept); - - $this->view->header = $header; - $this->view->position = $position; - $this->view->user = $user; - - $this->view->deptPath = $deptPath; - - $this->display(); - } - - /** - * Set the rerferer. - * - * @param string $referer - * @access public - * @return void - */ - public function setReferer($referer = '') - { - if(!empty($referer)) - { - $this->referer = helper::safe64Decode($referer); - } - else - { - $this->referer = $this->server->http_referer ? $this->server->http_referer: ''; - } - } - - /** - * Create a suer. - * - * @param int $deptID - * @access public - * @return void - */ - public function create($deptID = 0) - { - $this->lang->set('menugroup.user', 'company'); - $this->lang->user->menu = $this->lang->company->menu; - - if(!empty($_POST)) - { - $this->user->create(); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('company', 'browse'), 'parent')); - } - - $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->user->create; - $position[] = $this->lang->user->create; - $this->view->header = $header; - $this->view->position = $position; - $this->view->depts = $this->dept->getOptionMenu(); - $this->view->deptID = $deptID; - - $this->display(); - } - - /** - * Edit a user. - * - * @param string|int $userID the int user id or account - * @access public - * @return void - */ - public function edit($userID) - { - $this->lang->set('menugroup.user', 'company'); - $this->lang->user->menu = $this->lang->company->menu; - if(!empty($_POST)) - { - $this->user->update($userID); - if(dao::isError()) die(js::error(dao::getError())); - die(js::locate($this->createLink('company', 'browse'), 'parent')); - } - - $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->user->edit; - $position[] = $this->lang->user->edit; - $this->view->header = $header; - $this->view->position = $position; - $this->view->user = $this->user->getById($userID); - $this->view->depts = $this->dept->getOptionMenu(); - - $this->display(); - } - - /** - * Delete a user. - * - * @param int $userID - * @param string $confirm yes|no - * @access public - * @return void - */ - public function delete($userID, $confirm = 'no') - { - if($confirm == 'no') - { - die(js::confirm($this->lang->user->confirmDelete, $this->createLink('user', 'delete', "userID=$userID&confirm=yes"))); - } - else - { - $this->user->delete(TABLE_USER, $userID); - die(js::locate($this->createLink('company', 'browse'), 'parent')); - } - } - - /** - * User login, identify him and authorize him. - * - * @access public - * @return void - */ - public function login($referer = '', $from = '') - { - $this->setReferer($referer); - - $loginLink = $this->createLink('user', 'login'); - $denyLink = $this->createLink('user', 'deny'); - - /* If user is logon, back to the rerferer. */ - if($this->user->isLogon()) - { - if(strpos($this->referer, $loginLink) === false and - strpos($this->referer, $denyLink) === false and - strpos($this->referer, $this->app->company->pms) !== false - ) - { - $this->locate($this->referer); - } - else - { - $this->locate($this->createLink($this->config->default->module)); - } - } - - /* Passed account and password by post or get. */ - if(!empty($_POST) or (isset($_GET['account']) and isset($_GET['password']))) - { - $account = ''; - $password = ''; - if($this->post->account) $account = $this->post->account; - if($this->get->account) $account = $this->get->account; - if($this->post->password) $password = $this->post->password; - if($this->get->password) $password = $this->get->password; - - $user = $this->user->identify($account, $password); - - if($user) - { - /* Authorize him and save to session. */ - $user->rights = $this->user->authorize($account); - $this->session->set('user', $user); - $this->app->user = $this->session->user; - $this->loadModel('action')->create('user', $user->id, 'login'); - - /* Keep login. */ - if($this->post->keepLogin) $this->user->keepLogin($user); - - /* Go to the referer. */ - if($this->post->referer and - strpos($this->post->referer, $loginLink) === false and - strpos($this->post->referer, $denyLink) === false - ) - { - if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'success'))); - - /* Get the module and method of the referer. */ - if($this->config->requestType == 'PATH_INFO') - { - $path = substr($this->post->referer, strrpos($this->post->referer, '/') + 1); - $path = rtrim($path, '.html'); - list($module, $method) = explode($this->config->requestFix, $path); - } - else - { - $url = html_entity_decode($this->post->referer); - $param = substr($url, strrpos($url, '?') + 1); - list($module, $method) = explode('&', $param); - $module = str_replace('m=', '', $module); - $method = str_replace('f=', '', $method); - } - - if(common::hasPriv($module, $method)) - { - die(js::locate($this->post->referer, 'parent')); - } - else - { - die(js::locate($this->createLink($this->config->default->module), 'parent')); - } - } - else - { - if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'success'))); - die(js::locate($this->createLink($this->config->default->module), 'parent')); - } - } - else - { - if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'failed'))); - die(js::error($this->lang->user->loginFailed)); - } - } - else - { - $header['title'] = $this->lang->user->login; - $this->view->header = $header; - $this->view->referer = $this->referer; - $this->view->s = $this->loadModel('setting')->getItem('system', 'global', 'sn'); - $this->view->keepLogin = $this->cookie->keepLogin ? $this->cookie->keepLogin : 'off'; - $this->display(); - } - } - - /** - * Deny page. - * - * @param string $module - * @param string $method - * @param string $refererBeforeDeny the referer of the denied page. - * @access public - * @return void - */ - public function deny($module, $method, $refererBeforeDeny = '') - { - $this->setReferer(); - $header['title'] = $this->lang->user->deny; - $this->view->header = $header; - $this->view->module = $module; - $this->view->method = $method; - $this->view->denyPage = $this->referer; // The denied page. - $this->view->refererBeforeDeny = $refererBeforeDeny; // The referer of the denied page. - $this->app->loadLang($module); - $this->app->loadLang('my'); - $this->display(); - exit; - } - - /** - * Logout. - * - * @access public - * @return void - */ - public function logout($referer = 0) - { - $this->loadModel('action')->create('user', $this->app->user->id, 'logout'); - session_destroy(); - setcookie('za', false); - setcookie('zp', false); - $vars = !empty($referer) ? "referer=$referer" : ''; - $this->locate($this->createLink('user', 'login', $vars)); - } - - /** - * User dynamic. - * - * @param string $period - * @param string $account - * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID - * @access public - * @return void - */ - public function dynamic($period = 'today', $account = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) - { - /* set menus. */ - $this->lang->set('menugroup.user', 'company'); - $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); - - /* Save session. */ - $uri = $this->app->getURI(true); - $this->session->set('productList', $uri); - $this->session->set('productPlanList', $uri); - $this->session->set('releaseList', $uri); - $this->session->set('storyList', $uri); - $this->session->set('projectList', $uri); - $this->session->set('taskList', $uri); - $this->session->set('buildList', $uri); - $this->session->set('bugList', $uri); - $this->session->set('caseList', $uri); - $this->session->set('testtaskList', $uri); - - /* Set the pager. */ - $this->app->loadClass('pager', $static = true); - $pager = pager::init($recTotal, $recPerPage, $pageID); - $this->view->orderBy = $orderBy; - $this->view->pager = $pager; - - $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic; - $this->view->position[] = $this->lang->company->dynamic; - - /* Assign. */ - $this->view->period = $period; - $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); - $this->view->account = $account; - $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager); - $this->display(); - } - - /** - * Get user for ajax - * - * @param string $requestID - * @param string $assignedTo - * @access public - * @return void - */ - public function ajaxGetUser($taskID = '', $assignedTo = '') - { - $users = $this->user->getPairs('noletter, noclosed'); - $html = "
              "; - $html .= html::select('assignedTo', $users, $assignedTo); - $html .= html::submitButton(); - $html .= '
              '; - echo $html; - } - -} + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +class user extends control +{ + private $referer; + + /** + * Construct + * + * @access public + * @return void + */ + public function __construct() + { + parent::__construct(); + $this->loadModel('company')->setMenu(); + $this->loadModel('dept'); + } + + /** + * View a user. + * + * @param string $account + * @access public + * @return void + */ + public function view($account) + { + $this->locate($this->createLink('user', 'profile', "account=$account")); + } + + /** + * Todos of a user. + * + * @param string $account + * @param string $type the tod type, today|lastweek|thisweek|all|undone, or a date. + * @param string $status + * @access public + * @return void + */ + public function todo($account, $type = 'today', $status = 'all') + { + /* Set thie url to session. */ + $uri = $this->app->getURI(true); + $this->session->set('todoList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('taskList', $uri); + + /* set menus. */ + $this->lang->set('menugroup.user', 'company'); + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + /* Get user, totos. */ + $user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); + $todos = $this->loadModel('todo')->getList($type, $account, $status); + $date = (int)$type == 0 ? $this->todo->today() : $type; + + $header['title'] = $this->lang->company->orgView . $this->lang->colon . $this->lang->user->todo; + $position[] = $this->lang->user->todo; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->tabID = 'todo'; + $this->view->dates = $this->todo->buildDateList(); + $this->view->date = $date; + $this->view->todos = $todos; + $this->view->user = $user; + $this->view->account = $account; + $this->view->type = $type; + + $this->display(); + } + + /** + * Taskes of a user. + * + * @param string $account + * @access public + * @return void + */ + public function task($account) + { + /* Save the session. */ + $this->session->set('taskList', $this->app->getURI(true)); + + /* Set the menu. */ + $this->lang->set('menugroup.user', 'company'); + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + /* Assign. */ + $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->task; + $position[] = $this->lang->user->task; + $this->view->header = $header; + $this->view->position = $position; + $this->view->tabID = 'task'; + $this->view->tasks = $this->loadModel('task')->getUserTasks($account); + $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); + + $this->display(); + } + + /** + * User bugs. + * + * @param string $account + * @access public + * @return void + */ + public function bug($account) + { + /* Save the session. */ + $this->session->set('bugList', $this->app->getURI(true)); + + /* Set menu. */ + $this->lang->set('menugroup.user', 'company'); + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + /* Load the lang of bug module. */ + $this->app->loadLang('bug'); + + $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->bug; + $position[] = $this->lang->user->bug; + + $this->view->header = $header; + $this->view->position = $position; + $this->view->tabID = 'bug'; + $this->view->bugs = $this->user->getBugs($account); + $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); + $this->view->users = $this->user->getPairs('noletter'); + + $this->display(); + } + + /** + * User projects. + * + * @param string $account + * @access public + * @return void + */ + public function project($account) + { + /* Set the menus. */ + $this->loadModel('project'); + $this->lang->set('menugroup.user', 'company'); + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->project; + $position[] = $this->lang->user->project; + $this->view->header = $header; + $this->view->position = $position; + $this->view->tabID = 'project'; + $this->view->projects = $this->user->getProjects($account); + $this->view->user = $this->dao->findByAccount($account)->from(TABLE_USER)->fetch(); + + $this->display(); + } + + /** + * The profile of a user. + * + * @param string $account + * @access public + * @return void + */ + public function profile($account) + { + $header['title'] = $this->lang->user->common . $this->lang->colon . $this->lang->user->profile; + $position[] = $this->lang->user->profile; + + /* Set menu. */ + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + $user = $this->user->getById($account); + $deptPath = $this->dept->getParents($user->dept); + + $this->view->header = $header; + $this->view->position = $position; + $this->view->user = $user; + + $this->view->deptPath = $deptPath; + + $this->display(); + } + + /** + * Set the rerferer. + * + * @param string $referer + * @access public + * @return void + */ + public function setReferer($referer = '') + { + if(!empty($referer)) + { + $this->referer = helper::safe64Decode($referer); + } + else + { + $this->referer = $this->server->http_referer ? $this->server->http_referer: ''; + } + } + + /** + * Create a suer. + * + * @param int $deptID + * @access public + * @return void + */ + public function create($deptID = 0) + { + $this->lang->set('menugroup.user', 'company'); + $this->lang->user->menu = $this->lang->company->menu; + + if(!empty($_POST)) + { + $this->user->create(); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('company', 'browse'), 'parent')); + } + + $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->user->create; + $position[] = $this->lang->user->create; + $this->view->header = $header; + $this->view->position = $position; + $this->view->depts = $this->dept->getOptionMenu(); + $this->view->deptID = $deptID; + + $this->display(); + } + + /** + * Edit a user. + * + * @param string|int $userID the int user id or account + * @access public + * @return void + */ + public function edit($userID) + { + $this->lang->set('menugroup.user', 'company'); + $this->lang->user->menu = $this->lang->company->menu; + if(!empty($_POST)) + { + $this->user->update($userID); + if(dao::isError()) die(js::error(dao::getError())); + die(js::locate($this->createLink('company', 'browse'), 'parent')); + } + + $header['title'] = $this->lang->company->common . $this->lang->colon . $this->lang->user->edit; + $position[] = $this->lang->user->edit; + $this->view->header = $header; + $this->view->position = $position; + $this->view->user = $this->user->getById($userID); + $this->view->depts = $this->dept->getOptionMenu(); + + $this->display(); + } + + /** + * Delete a user. + * + * @param int $userID + * @param string $confirm yes|no + * @access public + * @return void + */ + public function delete($userID, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->user->confirmDelete, $this->createLink('user', 'delete', "userID=$userID&confirm=yes"))); + } + else + { + $this->user->delete(TABLE_USER, $userID); + die(js::locate($this->createLink('company', 'browse'), 'parent')); + } + } + + /** + * User login, identify him and authorize him. + * + * @access public + * @return void + */ + public function login($referer = '', $from = '') + { + $this->setReferer($referer); + + $loginLink = $this->createLink('user', 'login'); + $denyLink = $this->createLink('user', 'deny'); + + /* If user is logon, back to the rerferer. */ + if($this->user->isLogon()) + { + if(strpos($this->referer, $loginLink) === false and + strpos($this->referer, $denyLink) === false and + strpos($this->referer, $this->app->company->pms) !== false + ) + { + $this->locate($this->referer); + } + else + { + $this->locate($this->createLink($this->config->default->module)); + } + } + + /* Passed account and password by post or get. */ + if(!empty($_POST) or (isset($_GET['account']) and isset($_GET['password']))) + { + $account = ''; + $password = ''; + if($this->post->account) $account = $this->post->account; + if($this->get->account) $account = $this->get->account; + if($this->post->password) $password = $this->post->password; + if($this->get->password) $password = $this->get->password; + + $user = $this->user->identify($account, $password); + + if($user) + { + /* Authorize him and save to session. */ + $user->rights = $this->user->authorize($account); + $this->session->set('user', $user); + $this->app->user = $this->session->user; + $this->loadModel('action')->create('user', $user->id, 'login'); + + /* Keep login. */ + if($this->post->keepLogin) $this->user->keepLogin($user); + + /* Go to the referer. */ + if($this->post->referer and + strpos($this->post->referer, $loginLink) === false and + strpos($this->post->referer, $denyLink) === false + ) + { + if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'success'))); + + /* Get the module and method of the referer. */ + if($this->config->requestType == 'PATH_INFO') + { + $path = substr($this->post->referer, strrpos($this->post->referer, '/') + 1); + $path = rtrim($path, '.html'); + list($module, $method) = explode($this->config->requestFix, $path); + } + else + { + $url = html_entity_decode($this->post->referer); + $param = substr($url, strrpos($url, '?') + 1); + list($module, $method) = explode('&', $param); + $module = str_replace('m=', '', $module); + $method = str_replace('f=', '', $method); + } + + if(common::hasPriv($module, $method)) + { + die(js::locate($this->post->referer, 'parent')); + } + else + { + die(js::locate($this->createLink($this->config->default->module), 'parent')); + } + } + else + { + if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'success'))); + die(js::locate($this->createLink($this->config->default->module), 'parent')); + } + } + else + { + if($this->app->getViewType() == 'json') die(json_encode(array('status' => 'failed'))); + die(js::error($this->lang->user->loginFailed)); + } + } + else + { + $header['title'] = $this->lang->user->login; + $this->view->header = $header; + $this->view->referer = $this->referer; + $this->view->s = $this->loadModel('setting')->getItem('system', 'global', 'sn'); + $this->view->keepLogin = $this->cookie->keepLogin ? $this->cookie->keepLogin : 'off'; + $this->display(); + } + } + + /** + * Deny page. + * + * @param string $module + * @param string $method + * @param string $refererBeforeDeny the referer of the denied page. + * @access public + * @return void + */ + public function deny($module, $method, $refererBeforeDeny = '') + { + $this->setReferer(); + $header['title'] = $this->lang->user->deny; + $this->view->header = $header; + $this->view->module = $module; + $this->view->method = $method; + $this->view->denyPage = $this->referer; // The denied page. + $this->view->refererBeforeDeny = $refererBeforeDeny; // The referer of the denied page. + $this->app->loadLang($module); + $this->app->loadLang('my'); + $this->display(); + exit; + } + + /** + * Logout. + * + * @access public + * @return void + */ + public function logout($referer = 0) + { + $this->loadModel('action')->create('user', $this->app->user->id, 'logout'); + session_destroy(); + setcookie('za', false); + setcookie('zp', false); + $vars = !empty($referer) ? "referer=$referer" : ''; + $this->locate($this->createLink('user', 'login', $vars)); + } + + /** + * User dynamic. + * + * @param string $period + * @param string $account + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function dynamic($period = 'today', $account = '', $orderBy = 'date_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + /* set menus. */ + $this->lang->set('menugroup.user', 'company'); + $this->user->setMenu($this->user->getPairs('noempty|noclosed'), $account); + + /* Save session. */ + $uri = $this->app->getURI(true); + $this->session->set('productList', $uri); + $this->session->set('productPlanList', $uri); + $this->session->set('releaseList', $uri); + $this->session->set('storyList', $uri); + $this->session->set('projectList', $uri); + $this->session->set('taskList', $uri); + $this->session->set('buildList', $uri); + $this->session->set('bugList', $uri); + $this->session->set('caseList', $uri); + $this->session->set('testtaskList', $uri); + + /* Set the pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + $this->view->orderBy = $orderBy; + $this->view->pager = $pager; + + $this->view->header->title = $this->lang->company->common . $this->lang->colon . $this->lang->company->dynamic; + $this->view->position[] = $this->lang->company->dynamic; + + /* Assign. */ + $this->view->period = $period; + $this->view->users = $this->loadModel('user')->getPairs('nodeleted|noletter'); + $this->view->account = $account; + $this->view->actions = $this->loadModel('action')->getDynamic($account, $period, $orderBy, $pager); + $this->display(); + } + + /** + * Get user for ajax + * + * @param string $requestID + * @param string $assignedTo + * @access public + * @return void + */ + public function ajaxGetUser($taskID = '', $assignedTo = '') + { + $users = $this->user->getPairs('noletter, noclosed'); + $html = "
              "; + $html .= html::select('assignedTo', $users, $assignedTo); + $html .= html::submitButton(); + $html .= '
              '; + echo $html; + } + +} diff --git a/module/user/lang/en.php b/module/user/lang/en.php index f2ee4acdc4..8625d9c146 100644 --- a/module/user/lang/en.php +++ b/module/user/lang/en.php @@ -1,82 +1,82 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->user->common = 'User'; -$lang->user->index = "Index"; -$lang->user->view = "Info"; -$lang->user->create = "Add"; -$lang->user->read = "Info"; -$lang->user->edit = "Edit"; -$lang->user->update = "Upgrade"; -$lang->user->delete = "Delete"; -$lang->user->browse = "Browse"; -$lang->user->login = "Login"; -$lang->user->userView = "User view"; -$lang->user->editProfile = "Edit profile"; -$lang->user->editPassword = "Change password"; -$lang->user->deny = "Denied"; -$lang->user->confirmDelete = "Are you sure to delete this user?"; -$lang->user->confirmActivate = "Are you sure to activate this user?"; -$lang->user->relogin = "Relogin"; -$lang->user->asGuest = "Guest"; -$lang->user->goback = "Back"; -$lang->user->allUsers = 'All users'; -$lang->user->deleted = '(deleted)'; -$lang->user->select = '--select user--'; - -$lang->user->profile = 'Profile'; -$lang->user->project = 'Project'; -$lang->user->task = 'Task'; -$lang->user->bug = 'Bug'; -$lang->user->todo = 'Todo'; -$lang->user->story = 'Story'; -$lang->user->team = 'Team'; -$lang->user->dynamic = 'Dynamic'; -$lang->user->ajaxGetUser = 'AJAX:get users'; -$lang->user->editProfile = 'Edit profile'; - -$lang->user->errorDeny = "Sorry, you can't access the %s module's %s feature"; -$lang->user->loginFailed = "Login failed, please check your account and password."; - -$lang->user->genderList->m = 'Male'; -$lang->user->genderList->f = 'Female'; - -$lang->user->statusList['active'] = 'Activate'; -$lang->user->statusList['delete'] = 'Deleted'; -$lang->user->keepLogin['on'] = 'Keep login'; - -$lang->user->id = 'ID'; -$lang->user->company = 'Company'; -$lang->user->dept = 'Department'; -$lang->user->account = 'Account'; -$lang->user->password = 'Password'; -$lang->user->password2 = 'Repeat password'; -$lang->user->realname = 'Fullname'; -$lang->user->nickname = 'Nickname'; -$lang->user->commiter = 'Commit account'; -$lang->user->avatar = 'Avatar'; -$lang->user->birthyear = 'Birth year'; -$lang->user->gender = 'Gender'; -$lang->user->email = 'Email'; -$lang->user->msn = 'MSN'; -$lang->user->qq = 'QQ'; -$lang->user->yahoo = 'Yahoo!'; -$lang->user->gtalk = 'GTalk'; -$lang->user->wangwang = 'Wangwang'; -$lang->user->mobile = 'Mobile'; -$lang->user->phone = 'Phone'; -$lang->user->address = 'Address'; -$lang->user->zipcode = 'Zipcode'; -$lang->user->join = 'Join date'; -$lang->user->visits = 'Visits'; -$lang->user->ip = 'Last IP'; -$lang->user->last = 'Last login'; -$lang->user->status = 'Status'; + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->user->common = 'User'; +$lang->user->index = "Index"; +$lang->user->view = "Info"; +$lang->user->create = "Add"; +$lang->user->read = "Info"; +$lang->user->edit = "Edit"; +$lang->user->update = "Upgrade"; +$lang->user->delete = "Delete"; +$lang->user->browse = "Browse"; +$lang->user->login = "Login"; +$lang->user->userView = "User view"; +$lang->user->editProfile = "Edit profile"; +$lang->user->editPassword = "Change password"; +$lang->user->deny = "Denied"; +$lang->user->confirmDelete = "Are you sure to delete this user?"; +$lang->user->confirmActivate = "Are you sure to activate this user?"; +$lang->user->relogin = "Relogin"; +$lang->user->asGuest = "Guest"; +$lang->user->goback = "Back"; +$lang->user->allUsers = 'All users'; +$lang->user->deleted = '(deleted)'; +$lang->user->select = '--select user--'; + +$lang->user->profile = 'Profile'; +$lang->user->project = 'Project'; +$lang->user->task = 'Task'; +$lang->user->bug = 'Bug'; +$lang->user->todo = 'Todo'; +$lang->user->story = 'Story'; +$lang->user->team = 'Team'; +$lang->user->dynamic = 'Dynamic'; +$lang->user->ajaxGetUser = 'AJAX:get users'; +$lang->user->editProfile = 'Edit profile'; + +$lang->user->errorDeny = "Sorry, you can't access the %s module's %s feature"; +$lang->user->loginFailed = "Login failed, please check your account and password."; + +$lang->user->genderList->m = 'Male'; +$lang->user->genderList->f = 'Female'; + +$lang->user->statusList['active'] = 'Activate'; +$lang->user->statusList['delete'] = 'Deleted'; +$lang->user->keepLogin['on'] = 'Keep login'; + +$lang->user->id = 'ID'; +$lang->user->company = 'Company'; +$lang->user->dept = 'Department'; +$lang->user->account = 'Account'; +$lang->user->password = 'Password'; +$lang->user->password2 = 'Repeat password'; +$lang->user->realname = 'Fullname'; +$lang->user->nickname = 'Nickname'; +$lang->user->commiter = 'Commit account'; +$lang->user->avatar = 'Avatar'; +$lang->user->birthyear = 'Birth year'; +$lang->user->gender = 'Gender'; +$lang->user->email = 'Email'; +$lang->user->msn = 'MSN'; +$lang->user->qq = 'QQ'; +$lang->user->yahoo = 'Yahoo!'; +$lang->user->gtalk = 'GTalk'; +$lang->user->wangwang = 'Wangwang'; +$lang->user->mobile = 'Mobile'; +$lang->user->phone = 'Phone'; +$lang->user->address = 'Address'; +$lang->user->zipcode = 'Zipcode'; +$lang->user->join = 'Join date'; +$lang->user->visits = 'Visits'; +$lang->user->ip = 'Last IP'; +$lang->user->last = 'Last login'; +$lang->user->status = 'Status'; diff --git a/module/user/lang/zh-cn.php b/module/user/lang/zh-cn.php index 339bd1987e..842a0daa4f 100644 --- a/module/user/lang/zh-cn.php +++ b/module/user/lang/zh-cn.php @@ -1,82 +1,82 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -$lang->user->common = '用户'; -$lang->user->index = "用户视图首页"; -$lang->user->view = "用户详情"; -$lang->user->create = "添加用户"; -$lang->user->read = "查看用户"; -$lang->user->edit = "编辑用户"; -$lang->user->update = "编辑用户"; -$lang->user->delete = "删除用户"; -$lang->user->browse = "浏览用户"; -$lang->user->login = "用户登录"; -$lang->user->userView = "人员视图"; -$lang->user->editProfile = "修改个人信息"; -$lang->user->editPassword = "修改密码"; -$lang->user->deny = "访问受限"; -$lang->user->confirmDelete = "您确认删除该用户吗?"; -$lang->user->confirmActivate = "您确认激活该用户吗?"; -$lang->user->relogin = "重新登录"; -$lang->user->asGuest = "游客访问"; -$lang->user->goback = "返回前一页"; -$lang->user->allUsers = '全部用户'; -$lang->user->deleted = '(已删除)'; -$lang->user->select = '--请选择用户--'; - -$lang->user->profile = '用户档案'; -$lang->user->project = '用户项目'; -$lang->user->task = '用户任务'; -$lang->user->bug = '用户Bug'; -$lang->user->todo = '用户TODO'; -$lang->user->story = '用户需求'; -$lang->user->team = '用户团队'; -$lang->user->dynamic = '用户动态'; -$lang->user->ajaxGetUser = '接口:获得用户'; -$lang->user->editProfile = '修改信息'; - -$lang->user->errorDeny = "抱歉,您无权访问『%s』模块的『%s』功能。请联系管理员获取权限。点击后退返回上页。"; -$lang->user->loginFailed = "登录失败,请检查您的用户名或密码是否填写正确。"; - -$lang->user->genderList->m = '男'; -$lang->user->genderList->f = '女'; - -$lang->user->statusList['active'] = '正常'; -$lang->user->statusList['delete'] = '删除'; -$lang->user->keepLogin['on'] = '保持登录'; - -$lang->user->id = '用户编号'; -$lang->user->company = '所属公司'; -$lang->user->dept = '所属部门'; -$lang->user->account = '用户名'; -$lang->user->password = '密码'; -$lang->user->password2 = '请重复密码'; -$lang->user->realname = '真实姓名'; -$lang->user->nickname = '昵称'; -$lang->user->commiter = '源代码提交帐号'; -$lang->user->avatar = '头像'; -$lang->user->birthyear = '出生年'; -$lang->user->gender = '性别'; -$lang->user->email = '邮箱'; -$lang->user->msn = 'MSN'; -$lang->user->qq = 'QQ'; -$lang->user->yahoo = '雅虎通'; -$lang->user->gtalk = 'GTalk'; -$lang->user->wangwang = '旺旺'; -$lang->user->mobile = '手机'; -$lang->user->phone = '电话'; -$lang->user->address = '通讯地址'; -$lang->user->zipcode = '邮编'; -$lang->user->join = '加入日期'; -$lang->user->visits = '访问次数'; -$lang->user->ip = '最后IP'; -$lang->user->last = '最后登录'; -$lang->user->status = '状态'; + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +$lang->user->common = '用户'; +$lang->user->index = "用户视图首页"; +$lang->user->view = "用户详情"; +$lang->user->create = "添加用户"; +$lang->user->read = "查看用户"; +$lang->user->edit = "编辑用户"; +$lang->user->update = "编辑用户"; +$lang->user->delete = "删除用户"; +$lang->user->browse = "浏览用户"; +$lang->user->login = "用户登录"; +$lang->user->userView = "人员视图"; +$lang->user->editProfile = "修改个人信息"; +$lang->user->editPassword = "修改密码"; +$lang->user->deny = "访问受限"; +$lang->user->confirmDelete = "您确认删除该用户吗?"; +$lang->user->confirmActivate = "您确认激活该用户吗?"; +$lang->user->relogin = "重新登录"; +$lang->user->asGuest = "游客访问"; +$lang->user->goback = "返回前一页"; +$lang->user->allUsers = '全部用户'; +$lang->user->deleted = '(已删除)'; +$lang->user->select = '--请选择用户--'; + +$lang->user->profile = '用户档案'; +$lang->user->project = '用户项目'; +$lang->user->task = '用户任务'; +$lang->user->bug = '用户Bug'; +$lang->user->todo = '用户TODO'; +$lang->user->story = '用户需求'; +$lang->user->team = '用户团队'; +$lang->user->dynamic = '用户动态'; +$lang->user->ajaxGetUser = '接口:获得用户'; +$lang->user->editProfile = '修改信息'; + +$lang->user->errorDeny = "抱歉,您无权访问『%s』模块的『%s』功能。请联系管理员获取权限。点击后退返回上页。"; +$lang->user->loginFailed = "登录失败,请检查您的用户名或密码是否填写正确。"; + +$lang->user->genderList->m = '男'; +$lang->user->genderList->f = '女'; + +$lang->user->statusList['active'] = '正常'; +$lang->user->statusList['delete'] = '删除'; +$lang->user->keepLogin['on'] = '保持登录'; + +$lang->user->id = '用户编号'; +$lang->user->company = '所属公司'; +$lang->user->dept = '所属部门'; +$lang->user->account = '用户名'; +$lang->user->password = '密码'; +$lang->user->password2 = '请重复密码'; +$lang->user->realname = '真实姓名'; +$lang->user->nickname = '昵称'; +$lang->user->commiter = '源代码提交帐号'; +$lang->user->avatar = '头像'; +$lang->user->birthyear = '出生年'; +$lang->user->gender = '性别'; +$lang->user->email = '邮箱'; +$lang->user->msn = 'MSN'; +$lang->user->qq = 'QQ'; +$lang->user->yahoo = '雅虎通'; +$lang->user->gtalk = 'GTalk'; +$lang->user->wangwang = '旺旺'; +$lang->user->mobile = '手机'; +$lang->user->phone = '电话'; +$lang->user->address = '通讯地址'; +$lang->user->zipcode = '邮编'; +$lang->user->join = '加入日期'; +$lang->user->visits = '访问次数'; +$lang->user->ip = '最后IP'; +$lang->user->last = '最后登录'; +$lang->user->status = '状态'; diff --git a/module/user/lang/zh-tw.php b/module/user/lang/zh-tw.php index 85eed465b2..6afc566e58 100644 --- a/module/user/lang/zh-tw.php +++ b/module/user/lang/zh-tw.php @@ -1,82 +1,82 @@ - - * @package user - * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ - * @link http://www.zentao.net - */ -$lang->user->common = '用戶'; -$lang->user->index = "用戶視圖首頁"; -$lang->user->view = "用戶詳情"; -$lang->user->create = "添加用戶"; -$lang->user->read = "查看用戶"; -$lang->user->edit = "編輯用戶"; -$lang->user->update = "編輯用戶"; -$lang->user->delete = "刪除用戶"; -$lang->user->browse = "瀏覽用戶"; -$lang->user->login = "用戶登錄"; -$lang->user->userView = "人員視圖"; -$lang->user->editProfile = "修改個人信息"; -$lang->user->editPassword = "修改密碼"; -$lang->user->deny = "訪問受限"; -$lang->user->confirmDelete = "您確認刪除該用戶嗎?"; -$lang->user->confirmActivate = "您確認激活該用戶嗎?"; -$lang->user->relogin = "重新登錄"; -$lang->user->asGuest = "遊客訪問"; -$lang->user->goback = "返回前一頁"; -$lang->user->allUsers = '全部用戶'; -$lang->user->deleted = '(已刪除)'; -$lang->user->select = '--請選擇用戶--'; - -$lang->user->profile = '用戶檔案'; -$lang->user->project = '用戶項目'; -$lang->user->task = '用戶任務'; -$lang->user->bug = '用戶Bug'; -$lang->user->todo = '用戶TODO'; -$lang->user->story = '用戶需求'; -$lang->user->team = '用戶團隊'; -$lang->user->dynamic = '用戶動態'; -$lang->user->ajaxGetUser = '介面:獲得用戶'; -$lang->user->editProfile = '修改信息'; - -$lang->user->errorDeny = "抱歉,您無權訪問『%s』模組的『%s』功能。請聯繫管理員獲取權限。點擊後退返回上頁。"; -$lang->user->loginFailed = "登錄失敗,請檢查您的用戶名或密碼是否填寫正確。"; - -$lang->user->genderList->m = '男'; -$lang->user->genderList->f = '女'; - -$lang->user->statusList['active'] = '正常'; -$lang->user->statusList['delete'] = '刪除'; -$lang->user->keepLogin['on'] = '保持登錄'; - -$lang->user->id = '用戶編號'; -$lang->user->company = '所屬公司'; -$lang->user->dept = '所屬部門'; -$lang->user->account = '用戶名'; -$lang->user->password = '密碼'; -$lang->user->password2 = '請重複密碼'; -$lang->user->realname = '真實姓名'; -$lang->user->nickname = '暱稱'; -$lang->user->commiter = '原始碼提交帳號'; -$lang->user->avatar = '頭像'; -$lang->user->birthyear = '出生年'; -$lang->user->gender = '性別'; -$lang->user->email = '郵箱'; -$lang->user->msn = 'MSN'; -$lang->user->qq = 'QQ'; -$lang->user->yahoo = '雅虎通'; -$lang->user->gtalk = 'GTalk'; -$lang->user->wangwang = '旺旺'; -$lang->user->mobile = '手機'; -$lang->user->phone = '電話'; -$lang->user->address = '通訊地址'; -$lang->user->zipcode = '郵編'; -$lang->user->join = '加入日期'; -$lang->user->visits = '訪問次數'; -$lang->user->ip = '最後IP'; -$lang->user->last = '最後登錄'; -$lang->user->status = '狀態'; + + * @package user + * @version $Id: zh-tw.php 2568 2012-02-09 06:56:35Z shiyangyangwork@yahoo.cn $ + * @link http://www.zentao.net + */ +$lang->user->common = '用戶'; +$lang->user->index = "用戶視圖首頁"; +$lang->user->view = "用戶詳情"; +$lang->user->create = "添加用戶"; +$lang->user->read = "查看用戶"; +$lang->user->edit = "編輯用戶"; +$lang->user->update = "編輯用戶"; +$lang->user->delete = "刪除用戶"; +$lang->user->browse = "瀏覽用戶"; +$lang->user->login = "用戶登錄"; +$lang->user->userView = "人員視圖"; +$lang->user->editProfile = "修改個人信息"; +$lang->user->editPassword = "修改密碼"; +$lang->user->deny = "訪問受限"; +$lang->user->confirmDelete = "您確認刪除該用戶嗎?"; +$lang->user->confirmActivate = "您確認激活該用戶嗎?"; +$lang->user->relogin = "重新登錄"; +$lang->user->asGuest = "遊客訪問"; +$lang->user->goback = "返回前一頁"; +$lang->user->allUsers = '全部用戶'; +$lang->user->deleted = '(已刪除)'; +$lang->user->select = '--請選擇用戶--'; + +$lang->user->profile = '用戶檔案'; +$lang->user->project = '用戶項目'; +$lang->user->task = '用戶任務'; +$lang->user->bug = '用戶Bug'; +$lang->user->todo = '用戶TODO'; +$lang->user->story = '用戶需求'; +$lang->user->team = '用戶團隊'; +$lang->user->dynamic = '用戶動態'; +$lang->user->ajaxGetUser = '介面:獲得用戶'; +$lang->user->editProfile = '修改信息'; + +$lang->user->errorDeny = "抱歉,您無權訪問『%s』模組的『%s』功能。請聯繫管理員獲取權限。點擊後退返回上頁。"; +$lang->user->loginFailed = "登錄失敗,請檢查您的用戶名或密碼是否填寫正確。"; + +$lang->user->genderList->m = '男'; +$lang->user->genderList->f = '女'; + +$lang->user->statusList['active'] = '正常'; +$lang->user->statusList['delete'] = '刪除'; +$lang->user->keepLogin['on'] = '保持登錄'; + +$lang->user->id = '用戶編號'; +$lang->user->company = '所屬公司'; +$lang->user->dept = '所屬部門'; +$lang->user->account = '用戶名'; +$lang->user->password = '密碼'; +$lang->user->password2 = '請重複密碼'; +$lang->user->realname = '真實姓名'; +$lang->user->nickname = '暱稱'; +$lang->user->commiter = '原始碼提交帳號'; +$lang->user->avatar = '頭像'; +$lang->user->birthyear = '出生年'; +$lang->user->gender = '性別'; +$lang->user->email = '郵箱'; +$lang->user->msn = 'MSN'; +$lang->user->qq = 'QQ'; +$lang->user->yahoo = '雅虎通'; +$lang->user->gtalk = 'GTalk'; +$lang->user->wangwang = '旺旺'; +$lang->user->mobile = '手機'; +$lang->user->phone = '電話'; +$lang->user->address = '通訊地址'; +$lang->user->zipcode = '郵編'; +$lang->user->join = '加入日期'; +$lang->user->visits = '訪問次數'; +$lang->user->ip = '最後IP'; +$lang->user->last = '最後登錄'; +$lang->user->status = '狀態'; diff --git a/module/user/model.php b/module/user/model.php index 0e12bfc4e3..dd9fb3186d 100644 --- a/module/user/model.php +++ b/module/user/model.php @@ -1,411 +1,411 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -?> -app->getMethodName(); - $selectHtml = html::select('account', $users, $account, "onchange=\"switchAccount(this.value, '$methodName')\""); - foreach($this->lang->user->menu as $key => $value) - { - $replace = ($key == 'account') ? $selectHtml : $account; - common::setMenuVars($this->lang->user->menu, $key, $replace); - } - } - - /** - * Get users list of current company. - * - * @access public - * @return void - */ - public function getList() - { - return $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq(0)->orderBy('account')->fetchAll(); - } - - /** - * Get the account=>relaname pairs. - * - * @param string $params noletter|noempty|noclosed|nodeleted|withguest, can be sets of theme - * @access public - * @return array - */ - public function getPairs($params = '') - { - $users = $this->dao->select('account, realname')->from(TABLE_USER) - ->where('deleted')->eq(0) - ->beginIF(strpos($params, 'nodeleted') !== false) - ->fi() - ->orderBy('account')->fetchPairs(); - foreach($users as $account => $realName) - { - $firstLetter = ucfirst(substr($account, 0, 1)) . ':'; - if(strpos($params, 'noletter') !== false) $firstLetter = ''; - $users[$account] = $firstLetter . ($realName ? $realName : $account); - } - if(strpos($params, 'noempty') === false) $users = array('' => '') + $users; - if(strpos($params, 'noclosed') === false) $users = $users + array('closed' => 'Closed'); - if(strpos($params, 'withguest') !== false) $users = $users + array('guest' => 'Guest'); - return $users; - } - - /** - * Get commiters from the user table. - * - * @access public - * @return array - */ - public function getCommiters() - { - $rawCommiters = $this->dao->select('commiter, account, realname')->from(TABLE_USER)->where('commiter')->ne('')->fetchAll(); - if(!$rawCommiters) return array(); - - $commiters = array(); - foreach($rawCommiters as $commiter) $commiters[$commiter->commiter] = $commiter->realname ? $commiter->realname : $commiter->account; - - return $commiters; - } - - /** - * Appened deleted users to the user list. - * - * @param array $users - * @param string $deleteds the deleted users, can be a list - * @access public - * @return array new user lists with deleted users. - */ - public function appendDeleted($users, $deleteds = '') - { - $deleteds = explode(',', $deleteds); - foreach($deleteds as $deleted) - { - if(!isset($users[$deleted])) $users[$deleted] = $deleted . $this->lang->user->deleted; - } - return $users; - } - - /** - * Get user list with email and real name. - * - * @param string|array $users - * @access public - * @return array - */ - public function getRealNameAndEmails($users) - { - $users = $this->dao->select('account, email, realname')->from(TABLE_USER)->where('account')->in($users)->fetchAll('account'); - if(!$users) return array(); - foreach($users as $account => $user) if($user->realname == '') $user->realname = $account; - return $users; - } - - /** - * Get user info by ID. - * - * @param int $userID - * @access public - * @return object|bool - */ - public function getById($userID) - { - $user = $this->dao->select('*')->from(TABLE_USER) - ->beginIF(is_numeric($userID))->where('id')->eq((int)$userID)->fi() - ->beginIF(!is_numeric($userID))->where('account')->eq($userID)->fi() - ->fetch(); - if(!$user) return false; - $user->last = date(DT_DATETIME1, $user->last); - return $user; - } - - /** - * Create a user. - * - * @access public - * @return void - */ - public function create() - { - if(!$this->checkPassword()) return; - - $user = fixer::input('post') - ->setDefault('join', '0000-00-00') - ->setIF($this->post->password1 != false, 'password', md5($this->post->password1)) - ->setIF($this->post->password1 == false, 'password', '') - ->remove('password1, password2') - ->get(); - - $this->dao->insert(TABLE_USER)->data($user) - ->autoCheck() - ->batchCheck($this->config->user->create->requiredFields, 'notempty') - ->check('account', 'unique') - ->check('account', 'account') - ->checkIF($this->post->email != false, 'email', 'email') - ->exec(); - } - - /** - * Update a user. - * - * @param int $userID - * @access public - * @return void - */ - public function update($userID) - { - if(!$this->checkPassword()) return; - - $oldUser = $this->getById($userID); - - $userID = (int)$userID; - $user = fixer::input('post') - ->setDefault('join', '0000-00-00') - ->setIF($this->post->password1 != false, 'password', md5($this->post->password1)) - ->remove('password1, password2') - ->specialChars('msn,qq,yahoo,gtalk,wangwang,mobile,phone,address,zipcode') - ->get(); - - $this->dao->update(TABLE_USER)->data($user) - ->autoCheck() - ->batchCheck($this->config->user->edit->requiredFields, 'notempty') - ->check('account', 'unique', "id != '$userID'") - ->check('account', 'account') - ->checkIF($this->post->email != false, 'email', 'email') - ->where('id')->eq((int)$userID) - ->exec(); - - /* If account changed, update the privilege. */ - if($this->post->account != $oldUser->account) - { - $this->dao->update(TABLE_USERGROUP)->set('account')->eq($this->post->account)->where('account')->eq($oldUser->account)->exec(); - if(strpos($this->app->company->admins, ',' . $oldUser->account . ',') !== false) - { - $admins = ',' . $this->post->account . ','; - $this->dao->update(TABLE_COMPANY)->set('admins')->eq($admins)->where('id')->eq($this->app->company->id)->exec(false); - } - } - } - - /** - * Check the passwds posted. - * - * @access public - * @return bool - */ - public function checkPassword() - { - if($this->post->password1 != false) - { - if($this->post->password1 != $this->post->password2) dao::$errors['password'][] = $this->lang->error->passwordsame; - if(!validater::checkReg($this->post->password1, '|(.){6,}|')) dao::$errors['password'][] = $this->lang->error->passwordrule; - } - return !dao::isError(); - } - - /** - * Identify a user. - * - * @param string $account the user account - * @param string $password the user password or auth hash - * @access public - * @return object - */ - public function identify($account, $password) - { - if(!$account or !$password) return false; - - /* Get the user first. If $password length is 32, don't add the password condition. */ - $user = $this->dao->select('*')->from(TABLE_USER) - ->where('account')->eq($account) - ->beginIF(strlen($password) < 32)->andWhere('password')->eq(md5($password))->fi() - ->andWhere('deleted')->eq(0) - ->fetch(); - - /* If the length of $password is 32 or 40, checking by the auth hash. */ - if($user and strlen($password) == 32) - { - $hash = $this->session->rand ? md5($user->password . $this->session->rand) : $user->password; - $user = $password == $hash ? $user : ''; - } - elseif($user and strlen($password) == 40) - { - $hash = sha1($user->account . $user->password . $user->last); - $user = $password == $hash ? $user : ''; - } - - if($user) - { - $ip = $this->server->remote_addr; - $last = $this->server->request_time; - $this->dao->update(TABLE_USER)->set('visits = visits + 1')->set('ip')->eq($ip)->set('last')->eq($last)->where('account')->eq($account)->exec(); - $user->last = date(DT_DATETIME1, $user->last); - } - return $user; - } - - /** - * Identify user by PHP_AUTH_USER. - * - * @access public - * @return void - */ - public function identifyByPhpAuth() - { - $account = $this->server->php_auth_user; - $password = $this->server->php_auth_pw; - $user = $this->identify($account, $password); - if(!$user) return false; - - $user->rights = $this->authorize($account); - $this->session->set('user', $user); - $this->app->user = $this->session->user; - $this->loadModel('action')->create('user', $user->id, 'login'); - } - - /** - * Identify user by cookie. - * - * @access public - * @return void - */ - public function identifyByCookie() - { - $account = $this->cookie->za; - $authHash = $this->cookie->zp; - $user = $this->identify($account, $authHash); - if(!$user) return false; - - $user->rights = $this->authorize($account); - $this->session->set('user', $user); - $this->app->user = $this->session->user; - $this->loadModel('action')->create('user', $user->id, 'login'); - - $this->keepLogin($user); - } - - /** - * Authorize a user. - * - * @param string $account - * @access public - * @return array the user rights. - */ - public function authorize($account) - { - $account = filter_var($account, FILTER_SANITIZE_STRING); - if(!$account) return false; - - $rights = array(); - if($account == 'guest') - { - $sql = $this->dao->select('module, method')->from(TABLE_GROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2') - ->on('t1.id = t2.group')->where('t1.name')->eq('guest'); - } - else - { - $sql = $this->dao->select('module, method')->from(TABLE_USERGROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2') - ->on('t1.group = t2.group') - ->where('t1.account')->eq($account); - } - $stmt = $sql->query(); - if(!$stmt) return $rights; - while($row = $stmt->fetch(PDO::FETCH_ASSOC)) - { - $rights[strtolower($row['module'])][strtolower($row['method'])] = true; - } - return $rights; - } - - /** - * Keep the user in login state. - * - * @param string $account - * @param string $password - * @access public - * @return void - */ - public function keepLogin($user) - { - setcookie('keepLogin', 'on', $this->config->cookieLife, $this->config->webRoot); - setcookie('za', $user->account, $this->config->cookieLife, $this->config->webRoot); - setcookie('zp', sha1($user->account . $user->password . $this->server->request_time), $this->config->cookieLife, $this->config->webRoot); - } - - /* - /** - * Judge a user is logon or not. - * - * @access public - * @return bool - */ - public function isLogon() - { - return ($this->session->user and $this->session->user->account != 'guest'); - } - - /** - * Get groups a user belongs to. - * - * @param string $account - * @access public - * @return array - */ - public function getGroups($account) - { - return $this->dao->findByAccount($account)->from(TABLE_USERGROUP)->fields('`group`')->fetchPairs(); - } - - /** - * Get projects a user participated. - * - * @param string $account - * @access public - * @return array - */ - public function getProjects($account) - { - return $this->dao->select('t1.*,t2.*')->from(TABLE_TEAM)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t1.account')->eq($account) - ->andWhere('t2.deleted')->eq(0) - ->fetchAll(); - } - - /** - * Get bugs assigned to a user. - * - * @param string $account - * @access public - * @return array - */ - public function getBugs($account) - { - return $this->dao->select('t1.*') - ->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) - ->andwhere('t1.assignedTo')->eq($account) - ->fetchAll(); - } -} + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +?> +app->getMethodName(); + $selectHtml = html::select('account', $users, $account, "onchange=\"switchAccount(this.value, '$methodName')\""); + foreach($this->lang->user->menu as $key => $value) + { + $replace = ($key == 'account') ? $selectHtml : $account; + common::setMenuVars($this->lang->user->menu, $key, $replace); + } + } + + /** + * Get users list of current company. + * + * @access public + * @return void + */ + public function getList() + { + return $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq(0)->orderBy('account')->fetchAll(); + } + + /** + * Get the account=>relaname pairs. + * + * @param string $params noletter|noempty|noclosed|nodeleted|withguest, can be sets of theme + * @access public + * @return array + */ + public function getPairs($params = '') + { + $users = $this->dao->select('account, realname')->from(TABLE_USER) + ->where('deleted')->eq(0) + ->beginIF(strpos($params, 'nodeleted') !== false) + ->fi() + ->orderBy('account')->fetchPairs(); + foreach($users as $account => $realName) + { + $firstLetter = ucfirst(substr($account, 0, 1)) . ':'; + if(strpos($params, 'noletter') !== false) $firstLetter = ''; + $users[$account] = $firstLetter . ($realName ? $realName : $account); + } + if(strpos($params, 'noempty') === false) $users = array('' => '') + $users; + if(strpos($params, 'noclosed') === false) $users = $users + array('closed' => 'Closed'); + if(strpos($params, 'withguest') !== false) $users = $users + array('guest' => 'Guest'); + return $users; + } + + /** + * Get commiters from the user table. + * + * @access public + * @return array + */ + public function getCommiters() + { + $rawCommiters = $this->dao->select('commiter, account, realname')->from(TABLE_USER)->where('commiter')->ne('')->fetchAll(); + if(!$rawCommiters) return array(); + + $commiters = array(); + foreach($rawCommiters as $commiter) $commiters[$commiter->commiter] = $commiter->realname ? $commiter->realname : $commiter->account; + + return $commiters; + } + + /** + * Appened deleted users to the user list. + * + * @param array $users + * @param string $deleteds the deleted users, can be a list + * @access public + * @return array new user lists with deleted users. + */ + public function appendDeleted($users, $deleteds = '') + { + $deleteds = explode(',', $deleteds); + foreach($deleteds as $deleted) + { + if(!isset($users[$deleted])) $users[$deleted] = $deleted . $this->lang->user->deleted; + } + return $users; + } + + /** + * Get user list with email and real name. + * + * @param string|array $users + * @access public + * @return array + */ + public function getRealNameAndEmails($users) + { + $users = $this->dao->select('account, email, realname')->from(TABLE_USER)->where('account')->in($users)->fetchAll('account'); + if(!$users) return array(); + foreach($users as $account => $user) if($user->realname == '') $user->realname = $account; + return $users; + } + + /** + * Get user info by ID. + * + * @param int $userID + * @access public + * @return object|bool + */ + public function getById($userID) + { + $user = $this->dao->select('*')->from(TABLE_USER) + ->beginIF(is_numeric($userID))->where('id')->eq((int)$userID)->fi() + ->beginIF(!is_numeric($userID))->where('account')->eq($userID)->fi() + ->fetch(); + if(!$user) return false; + $user->last = date(DT_DATETIME1, $user->last); + return $user; + } + + /** + * Create a user. + * + * @access public + * @return void + */ + public function create() + { + if(!$this->checkPassword()) return; + + $user = fixer::input('post') + ->setDefault('join', '0000-00-00') + ->setIF($this->post->password1 != false, 'password', md5($this->post->password1)) + ->setIF($this->post->password1 == false, 'password', '') + ->remove('password1, password2') + ->get(); + + $this->dao->insert(TABLE_USER)->data($user) + ->autoCheck() + ->batchCheck($this->config->user->create->requiredFields, 'notempty') + ->check('account', 'unique') + ->check('account', 'account') + ->checkIF($this->post->email != false, 'email', 'email') + ->exec(); + } + + /** + * Update a user. + * + * @param int $userID + * @access public + * @return void + */ + public function update($userID) + { + if(!$this->checkPassword()) return; + + $oldUser = $this->getById($userID); + + $userID = (int)$userID; + $user = fixer::input('post') + ->setDefault('join', '0000-00-00') + ->setIF($this->post->password1 != false, 'password', md5($this->post->password1)) + ->remove('password1, password2') + ->specialChars('msn,qq,yahoo,gtalk,wangwang,mobile,phone,address,zipcode') + ->get(); + + $this->dao->update(TABLE_USER)->data($user) + ->autoCheck() + ->batchCheck($this->config->user->edit->requiredFields, 'notempty') + ->check('account', 'unique', "id != '$userID'") + ->check('account', 'account') + ->checkIF($this->post->email != false, 'email', 'email') + ->where('id')->eq((int)$userID) + ->exec(); + + /* If account changed, update the privilege. */ + if($this->post->account != $oldUser->account) + { + $this->dao->update(TABLE_USERGROUP)->set('account')->eq($this->post->account)->where('account')->eq($oldUser->account)->exec(); + if(strpos($this->app->company->admins, ',' . $oldUser->account . ',') !== false) + { + $admins = ',' . $this->post->account . ','; + $this->dao->update(TABLE_COMPANY)->set('admins')->eq($admins)->where('id')->eq($this->app->company->id)->exec(false); + } + } + } + + /** + * Check the passwds posted. + * + * @access public + * @return bool + */ + public function checkPassword() + { + if($this->post->password1 != false) + { + if($this->post->password1 != $this->post->password2) dao::$errors['password'][] = $this->lang->error->passwordsame; + if(!validater::checkReg($this->post->password1, '|(.){6,}|')) dao::$errors['password'][] = $this->lang->error->passwordrule; + } + return !dao::isError(); + } + + /** + * Identify a user. + * + * @param string $account the user account + * @param string $password the user password or auth hash + * @access public + * @return object + */ + public function identify($account, $password) + { + if(!$account or !$password) return false; + + /* Get the user first. If $password length is 32, don't add the password condition. */ + $user = $this->dao->select('*')->from(TABLE_USER) + ->where('account')->eq($account) + ->beginIF(strlen($password) < 32)->andWhere('password')->eq(md5($password))->fi() + ->andWhere('deleted')->eq(0) + ->fetch(); + + /* If the length of $password is 32 or 40, checking by the auth hash. */ + if($user and strlen($password) == 32) + { + $hash = $this->session->rand ? md5($user->password . $this->session->rand) : $user->password; + $user = $password == $hash ? $user : ''; + } + elseif($user and strlen($password) == 40) + { + $hash = sha1($user->account . $user->password . $user->last); + $user = $password == $hash ? $user : ''; + } + + if($user) + { + $ip = $this->server->remote_addr; + $last = $this->server->request_time; + $this->dao->update(TABLE_USER)->set('visits = visits + 1')->set('ip')->eq($ip)->set('last')->eq($last)->where('account')->eq($account)->exec(); + $user->last = date(DT_DATETIME1, $user->last); + } + return $user; + } + + /** + * Identify user by PHP_AUTH_USER. + * + * @access public + * @return void + */ + public function identifyByPhpAuth() + { + $account = $this->server->php_auth_user; + $password = $this->server->php_auth_pw; + $user = $this->identify($account, $password); + if(!$user) return false; + + $user->rights = $this->authorize($account); + $this->session->set('user', $user); + $this->app->user = $this->session->user; + $this->loadModel('action')->create('user', $user->id, 'login'); + } + + /** + * Identify user by cookie. + * + * @access public + * @return void + */ + public function identifyByCookie() + { + $account = $this->cookie->za; + $authHash = $this->cookie->zp; + $user = $this->identify($account, $authHash); + if(!$user) return false; + + $user->rights = $this->authorize($account); + $this->session->set('user', $user); + $this->app->user = $this->session->user; + $this->loadModel('action')->create('user', $user->id, 'login'); + + $this->keepLogin($user); + } + + /** + * Authorize a user. + * + * @param string $account + * @access public + * @return array the user rights. + */ + public function authorize($account) + { + $account = filter_var($account, FILTER_SANITIZE_STRING); + if(!$account) return false; + + $rights = array(); + if($account == 'guest') + { + $sql = $this->dao->select('module, method')->from(TABLE_GROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2') + ->on('t1.id = t2.group')->where('t1.name')->eq('guest'); + } + else + { + $sql = $this->dao->select('module, method')->from(TABLE_USERGROUP)->alias('t1')->leftJoin(TABLE_GROUPPRIV)->alias('t2') + ->on('t1.group = t2.group') + ->where('t1.account')->eq($account); + } + $stmt = $sql->query(); + if(!$stmt) return $rights; + while($row = $stmt->fetch(PDO::FETCH_ASSOC)) + { + $rights[strtolower($row['module'])][strtolower($row['method'])] = true; + } + return $rights; + } + + /** + * Keep the user in login state. + * + * @param string $account + * @param string $password + * @access public + * @return void + */ + public function keepLogin($user) + { + setcookie('keepLogin', 'on', $this->config->cookieLife, $this->config->webRoot); + setcookie('za', $user->account, $this->config->cookieLife, $this->config->webRoot); + setcookie('zp', sha1($user->account . $user->password . $this->server->request_time), $this->config->cookieLife, $this->config->webRoot); + } + + /* + /** + * Judge a user is logon or not. + * + * @access public + * @return bool + */ + public function isLogon() + { + return ($this->session->user and $this->session->user->account != 'guest'); + } + + /** + * Get groups a user belongs to. + * + * @param string $account + * @access public + * @return array + */ + public function getGroups($account) + { + return $this->dao->findByAccount($account)->from(TABLE_USERGROUP)->fields('`group`')->fetchPairs(); + } + + /** + * Get projects a user participated. + * + * @param string $account + * @access public + * @return array + */ + public function getProjects($account) + { + return $this->dao->select('t1.*,t2.*')->from(TABLE_TEAM)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.account')->eq($account) + ->andWhere('t2.deleted')->eq(0) + ->fetchAll(); + } + + /** + * Get bugs assigned to a user. + * + * @param string $account + * @access public + * @return array + */ + public function getBugs($account) + { + return $this->dao->select('t1.*') + ->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) + ->andwhere('t1.assignedTo')->eq($account) + ->fetchAll(); + } +} diff --git a/module/user/view/bug.html.php b/module/user/view/bug.html.php index 136df17fef..49dcb59cc7 100644 --- a/module/user/view/bug.html.php +++ b/module/user/view/bug.html.php @@ -1,43 +1,43 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              idAB;?>bug->severityAB;?>priAB;?>typeAB;?>bug->title;?>openedByAB;?>bug->resolvedBy;?>bug->resolutionAB;?>
              createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>bug->typeList[$bug->type]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>
              - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              idAB;?>bug->severityAB;?>priAB;?>typeAB;?>bug->title;?>openedByAB;?>bug->resolvedBy;?>bug->resolutionAB;?>
              createLink('bug', 'view', "bugID=$bug->id"), $bug->id, '_blank');?>bug->severityList[$bug->severity]?>bug->priList[$bug->pri]?>bug->typeList[$bug->type]?>createLink('bug', 'view', "bugID=$bug->id"), $bug->title);?>openedBy];?>resolvedBy];?>bug->resolutionList[$bug->resolution];?>
              + diff --git a/module/user/view/create.html.php b/module/user/view/create.html.php index 1742a1c82c..0ef8160889 100644 --- a/module/user/view/create.html.php +++ b/module/user/view/create.html.php @@ -1,57 +1,57 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              user->create;?>
              user->dept;?> -
              user->account;?>
              user->realname;?>
              user->commiter;?>
              user->email;?>
              user->join;?>
              user->gender;?>user->genderList, 'm');?>
              user->password;?>
              user->password2;?>
              -
              - + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              user->create;?>
              user->dept;?> +
              user->account;?>
              user->realname;?>
              user->commiter;?>
              user->email;?>
              user->join;?>
              user->gender;?>user->genderList, 'm');?>
              user->password;?>
              user->password2;?>
              +
              + diff --git a/module/user/view/deny.html.php b/module/user/view/deny.html.php index 78f60cf436..4cd87cd538 100644 --- a/module/user/view/deny.html.php +++ b/module/user/view/deny.html.php @@ -1,31 +1,31 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -include '../../common/view/header.lite.html.php'; -?> - - - - - -
              user->account, ' ', $lang->user->deny;?>
              - $module->common) ? $lang->$module->common: $module; - $methodName = isset($lang->$module->$method) ? $lang->$module->$method: $method; - - printf($lang->user->errorDeny, $moduleName, $methodName); - echo "
              "; - echo html::a($this->createLink($config->default->module), $lang->my->common); - if($refererBeforeDeny) echo html::a(helper::safe64Decode($refererBeforeDeny), $lang->user->goback); - echo html::a($this->createLink('user', 'logout', "referer=" . helper::safe64Encode($denyPage)), $lang->user->relogin); - ?> -
              - - + + * @package ZenTaoPMS + * @version $Id$ + */ +include '../../common/view/header.lite.html.php'; +?> + + + + + +
              user->account, ' ', $lang->user->deny;?>
              + $module->common) ? $lang->$module->common: $module; + $methodName = isset($lang->$module->$method) ? $lang->$module->$method: $method; + + printf($lang->user->errorDeny, $moduleName, $methodName); + echo "
              "; + echo html::a($this->createLink($config->default->module), $lang->my->common); + if($refererBeforeDeny) echo html::a(helper::safe64Decode($refererBeforeDeny), $lang->user->goback); + echo html::a($this->createLink('user', 'logout', "referer=" . helper::safe64Encode($denyPage)), $lang->user->relogin); + ?> +
              + + diff --git a/module/user/view/dynamic.html.php b/module/user/view/dynamic.html.php index 09fc5911c4..30a4c16d48 100644 --- a/module/user/view/dynamic.html.php +++ b/module/user/view/dynamic.html.php @@ -1,58 +1,58 @@ -dynamic view file of dashboard module of ZenTaoPMS. - * - * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) - * @license LGPL (http://www.gnu.org/licenses/lgpl.html) - * @author Chunsheng Wang - * @package dashboard - * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ - * @link http://www.zentao.net - */ -?> - - -
              - ' . html::a(inlink('dynamic', "type=today&account=$account"), $lang->action->dynamic->today) . ''; - echo '' . html::a(inlink('dynamic', "type=yesterday&account=$account"), $lang->action->dynamic->yesterday) . ''; - echo '' . html::a(inlink('dynamic', "type=twodaysago&account=$account"), $lang->action->dynamic->twoDaysAgo) . ''; - echo '' . html::a(inlink('dynamic', "type=thisweek&account=$account"), $lang->action->dynamic->thisWeek) . ''; - echo '' . html::a(inlink('dynamic', "type=lastweek&account=$account"), $lang->action->dynamic->lastWeek) . ''; - echo '' . html::a(inlink('dynamic', "type=thismonth&account=$account"), $lang->action->dynamic->thisMonth) . ''; - echo '' . html::a(inlink('dynamic', "type=lastmonth&account=$account"), $lang->action->dynamic->lastMonth) . ''; - echo '' . html::a(inlink('dynamic', "type=all&account=$account"), $lang->action->dynamic->all) . ''; - ?> -
              - - - - - - - - - - - - - - - objectType == 'case' ? 'testcase' : $action->objectType;?> - - - - - - - - - - - -
              action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
              date;?>actor];?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
              show();?>
              - - +dynamic view file of dashboard module of ZenTaoPMS. + * + * @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com) + * @license LGPL (http://www.gnu.org/licenses/lgpl.html) + * @author Chunsheng Wang + * @package dashboard + * @version $Id: action->dynamic.html.php 1477 2011-03-01 15:25:50Z wwccss $ + * @link http://www.zentao.net + */ +?> + + +
              + ' . html::a(inlink('dynamic', "type=today&account=$account"), $lang->action->dynamic->today) . ''; + echo '' . html::a(inlink('dynamic', "type=yesterday&account=$account"), $lang->action->dynamic->yesterday) . ''; + echo '' . html::a(inlink('dynamic', "type=twodaysago&account=$account"), $lang->action->dynamic->twoDaysAgo) . ''; + echo '' . html::a(inlink('dynamic', "type=thisweek&account=$account"), $lang->action->dynamic->thisWeek) . ''; + echo '' . html::a(inlink('dynamic', "type=lastweek&account=$account"), $lang->action->dynamic->lastWeek) . ''; + echo '' . html::a(inlink('dynamic', "type=thismonth&account=$account"), $lang->action->dynamic->thisMonth) . ''; + echo '' . html::a(inlink('dynamic', "type=lastmonth&account=$account"), $lang->action->dynamic->lastMonth) . ''; + echo '' . html::a(inlink('dynamic', "type=all&account=$account"), $lang->action->dynamic->all) . ''; + ?> +
              + + + + + + + + + + + + + + + objectType == 'case' ? 'testcase' : $action->objectType;?> + + + + + + + + + + + +
              action->date;?> action->actor;?>action->action;?> action->objectType;?> idAB;?>action->objectName;?>
              date;?>actor];?>actionLabel;?>action->objectTypes[$action->objectType];?>objectID;?>objectLink, $action->objectName);?>
              show();?>
              + + diff --git a/module/user/view/edit.html.php b/module/user/view/edit.html.php index fc63fb0146..e542f079ab 100644 --- a/module/user/view/edit.html.php +++ b/module/user/view/edit.html.php @@ -1,93 +1,93 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              user->edit;?>
              user->dept;?>dept, "class='select-3'");?> -
              user->account;?>account, "class='text-3'");?>
              user->realname;?>realname, "class='text-3'");?>
              user->commiter;?>commiter, "class='text-3'");?>
              user->email;?>email, "class='text-3'");?>
              user->join;?>join, "class='text-3 date'");?>
              user->gender;?>user->genderList, $user->gender);?>
              user->password;?>
              user->password2;?>
              user->msn;?>msn, "class='text-3'");?>
              user->qq;?>qq, "class='text-3'");?>
              user->yahoo;?>yahoo, "class='text-3'");?>
              user->gtalk;?>gtalk, "class='text-3'");?>
              user->wangwang;?>wangwang, "class='text-3'");?>
              user->mobile;?>mobile, "class='text-3'");?>
              user->phone;?>phone, "class='text-3'");?>
              user->address;?>address, "class='text-3'");?>
              user->zipcode;?>zipcode, "class='text-3'");?>
              -
              - + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              user->edit;?>
              user->dept;?>dept, "class='select-3'");?> +
              user->account;?>account, "class='text-3'");?>
              user->realname;?>realname, "class='text-3'");?>
              user->commiter;?>commiter, "class='text-3'");?>
              user->email;?>email, "class='text-3'");?>
              user->join;?>join, "class='text-3 date'");?>
              user->gender;?>user->genderList, $user->gender);?>
              user->password;?>
              user->password2;?>
              user->msn;?>msn, "class='text-3'");?>
              user->qq;?>qq, "class='text-3'");?>
              user->yahoo;?>yahoo, "class='text-3'");?>
              user->gtalk;?>gtalk, "class='text-3'");?>
              user->wangwang;?>wangwang, "class='text-3'");?>
              user->mobile;?>mobile, "class='text-3'");?>
              user->phone;?>phone, "class='text-3'");?>
              user->address;?>address, "class='text-3'");?>
              user->zipcode;?>zipcode, "class='text-3'");?>
              +
              + diff --git a/module/user/view/login.html.php b/module/user/view/login.html.php index d5563253ca..b0b52e51ed 100644 --- a/module/user/view/login.html.php +++ b/module/user/view/login.html.php @@ -1,50 +1,50 @@ - - * @package ZenTaoPMS - * @version $Id$ - */ -include '../../common/view/header.lite.html.php'; -include '../../common/view/colorbox.html.php'; -?> -
              - - - - - - - - - - - - - - - - - - -
              welcome, $app->company->name);?>
              user->account;?>:
              user->password;?>:
              Language:langs, $this->app->getClientLang(), 'class=select-2 onchange=selectLang(this.value)');?>
              user->keepLogin, $keepLogin);?>
              - login); - if($app->company->guest) echo html::linkButton($lang->user->asGuest, $this->createLink($config->default->module)); - echo html::hidden('referer', $referer); - ?> -
              -
              - powered by ZenTaoPMS(version;?>) - donate;?> -
              - -
              -
              - - + + * @package ZenTaoPMS + * @version $Id$ + */ +include '../../common/view/header.lite.html.php'; +include '../../common/view/colorbox.html.php'; +?> +
              + + + + + + + + + + + + + + + + + + +
              welcome, $app->company->name);?>
              user->account;?>:
              user->password;?>:
              Language:langs, $this->app->getClientLang(), 'class=select-2 onchange=selectLang(this.value)');?>
              user->keepLogin, $keepLogin);?>
              + login); + if($app->company->guest) echo html::linkButton($lang->user->asGuest, $this->createLink($config->default->module)); + echo html::hidden('referer', $referer); + ?> +
              +
              + powered by ZenTaoPMS(version;?>) + donate;?> +
              + +
              +
              + + diff --git a/module/user/view/profile.html.php b/module/user/view/profile.html.php index 2608d394e5..ec3c8b1628 100644 --- a/module/user/view/profile.html.php +++ b/module/user/view/profile.html.php @@ -1,119 +1,119 @@ - - * @package user - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              user->profile;?>
              user->dept;?> - $dept) - { - if($dept->name) echo $dept->name; - if(isset($deptPath[$key + 1])) echo $lang->arrow; - } - } - ?> -
              user->account;?>account;?>
              user->realname;?>realname;?>
              user->commiter;?>commiter;?>
              user->email;?>email;?>
              user->join;?>join;?>
              user->visits;?>visits;?>
              user->ip;?>ip;?>
              user->last;?>last;?>
              user->msn;?>msn;?>
              user->qq;?>qq;?>
              user->yahoo;?>yahoo;?>
              user->gtalk;?>gtalk;?>
              user->wangwang;?>wangwang;?>
              user->mobile;?>mobile;?>
              user->phone;?>phone;?>
              user->address;?>address;?>
              user->zipcode;?>zipcode;?>
              - createLink('user', 'edit', "userID=$user->id&from=company"), $lang->user->editProfile); - echo html::a($this->createLink('user', 'logout'), $lang->logout); - ?> -
              - + + * @package user + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              user->profile;?>
              user->dept;?> + $dept) + { + if($dept->name) echo $dept->name; + if(isset($deptPath[$key + 1])) echo $lang->arrow; + } + } + ?> +
              user->account;?>account;?>
              user->realname;?>realname;?>
              user->commiter;?>commiter;?>
              user->email;?>email;?>
              user->join;?>join;?>
              user->visits;?>visits;?>
              user->ip;?>ip;?>
              user->last;?>last;?>
              user->msn;?>msn;?>
              user->qq;?>qq;?>
              user->yahoo;?>yahoo;?>
              user->gtalk;?>gtalk;?>
              user->wangwang;?>wangwang;?>
              user->mobile;?>mobile;?>
              user->phone;?>phone;?>
              user->address;?>address;?>
              user->zipcode;?>zipcode;?>
              + createLink('user', 'edit', "userID=$user->id&from=company"), $lang->user->editProfile); + echo html::a($this->createLink('user', 'logout'), $lang->logout); + ?> +
              + diff --git a/module/user/view/project.html.php b/module/user/view/project.html.php index 289a8a0154..e05ec7cf72 100644 --- a/module/user/view/project.html.php +++ b/module/user/view/project.html.php @@ -1,46 +1,46 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - createLink('project', 'browse', "projectID=$project->id");?> - - - - - - - - - - - - - -
              idAB;?>project->code;?>project->name;?>project->begin;?>project->end;?>statusAB;?>team->role;?>team->join;?>team->hours;?>
              id);?>code;?>name);?>begin;?>end;?>project->statusList[$project->status];?>role;?>join;?>hours;?>
              - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + createLink('project', 'browse', "projectID=$project->id");?> + + + + + + + + + + + + + +
              idAB;?>project->code;?>project->name;?>project->begin;?>project->end;?>statusAB;?>team->role;?>team->join;?>team->hours;?>
              id);?>code;?>name);?>begin;?>end;?>project->statusList[$project->status];?>role;?>join;?>hours;?>
              + diff --git a/module/user/view/story.html.php b/module/user/view/story.html.php index 99559689f0..4b6aa4c632 100644 --- a/module/user/view/story.html.php +++ b/module/user/view/story.html.php @@ -1,15 +1,15 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + diff --git a/module/user/view/task.html.php b/module/user/view/task.html.php index c0fe6c5baa..52c3302447 100644 --- a/module/user/view/task.html.php +++ b/module/user/view/task.html.php @@ -1,44 +1,44 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              idAB;?>priAB;?>task->project;?>task->name;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>
              createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>task->priList[$task->pri];?>createLink('project', 'browse', "projectid=$task->projectID"), $task->projectName);?> - createLink('task', 'view', "taskID=$task->id"), $task->name);?>estimate;?>consumed;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>task->statusList[$task->status];?>
              - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              idAB;?>priAB;?>task->project;?>task->name;?>task->estimateAB;?>task->consumedAB;?>task->leftAB;?>task->deadlineAB;?>statusAB;?>
              createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));?>task->priList[$task->pri];?>createLink('project', 'browse', "projectid=$task->projectID"), $task->projectName);?> + createLink('task', 'view', "taskID=$task->id"), $task->name);?>estimate;?>consumed;?>left;?>delay)) echo 'delayed';?>>deadline, 0, 4) > 0) echo $task->deadline;?>task->statusList[$task->status];?>
              + diff --git a/module/user/view/team.html.php b/module/user/view/team.html.php index 7030b367d6..95c5ad5ce6 100644 --- a/module/user/view/team.html.php +++ b/module/user/view/team.html.php @@ -1,14 +1,14 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + diff --git a/module/user/view/todo.html.php b/module/user/view/todo.html.php index 7224b346d4..077be3cccd 100644 --- a/module/user/view/todo.html.php +++ b/module/user/view/todo.html.php @@ -1,60 +1,60 @@ - - * @package dashboard - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - - -
              ' id='todoform'> -
              -
              - ' . html::a(inlink('todo', "account=$account&date=today"), $lang->todo->todayTodos) . ''; - echo '' . html::a(inlink('todo', "account=$account&date=thisweek"), $lang->todo->thisWeekTodos) . ''; - echo '' . html::a(inlink('todo', "account=$account&date=lastweek"), $lang->todo->lastWeekTodos) . ''; - echo '' . html::a(inlink('todo', "account=$account&date=all"), $lang->todo->allDaysTodos) . ''; - echo '' . html::a(inlink('todo', "account=$account&date=before&status=undone"), $lang->todo->allUndone) . ''; - echo "" . html::select('date', $dates, $date, 'onchange=changeDate(this.value)') . ''; - ?> - -
              -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              idAB;?>todo->date;?>todo->type;?>priAB;?>todo->name;?>todo->beginAB;?>todo->endAB;?>todo->status;?>
              id;?>date == '2030-01-01' ? $lang->todo->dayInFuture : $todo->date;?>todo->typeList->{$todo->type};?>pri;?>id", $todo->name)) echo $todo->name;?>begin;?>end;?>todo->statusList[$todo->status];?>
              -
              - + + * @package dashboard + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + + +
              ' id='todoform'> +
              +
              + ' . html::a(inlink('todo', "account=$account&date=today"), $lang->todo->todayTodos) . ''; + echo '' . html::a(inlink('todo', "account=$account&date=thisweek"), $lang->todo->thisWeekTodos) . ''; + echo '' . html::a(inlink('todo', "account=$account&date=lastweek"), $lang->todo->lastWeekTodos) . ''; + echo '' . html::a(inlink('todo', "account=$account&date=all"), $lang->todo->allDaysTodos) . ''; + echo '' . html::a(inlink('todo', "account=$account&date=before&status=undone"), $lang->todo->allUndone) . ''; + echo "" . html::select('date', $dates, $date, 'onchange=changeDate(this.value)') . ''; + ?> + +
              +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              idAB;?>todo->date;?>todo->type;?>priAB;?>todo->name;?>todo->beginAB;?>todo->endAB;?>todo->status;?>
              id;?>date == '2030-01-01' ? $lang->todo->dayInFuture : $todo->date;?>todo->typeList->{$todo->type};?>pri;?>id", $todo->name)) echo $todo->name;?>begin;?>end;?>todo->statusList[$todo->status];?>
              +
              + diff --git a/module/user/view/view.html.php b/module/user/view/view.html.php index 2a0baf5d7c..ead760ab85 100644 --- a/module/user/view/view.html.php +++ b/module/user/view/view.html.php @@ -1,78 +1,78 @@ - - * @package my - * @version $Id$ - * @link http://www.zentao.net - */ -?> - - -
              -
              - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              my->profile;?>
              user->account;?>account;?>
              user->realname;?>realname;?>
              user->nickname;?>nickname;?>
              user->commiter;?>commiter;?>
              user->join;?>join;?>
              user->visits;?>visits;?>
              user->ip;?>ip;?>
              user->last;?>last;?>
              - -
              -
              -
              -
              -
                - {$user->realname}"; - echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=task"), $lang->my->task) . "
              • "; - //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=todo"), $lang->my->todo) . "
              • "; - echo "
              • ". html::a($this->createLink('user', 'view', "account=$user->account&tabID=project"), $lang->my->myProject) . "
              • "; - //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=story"), $lang->my->story) . "
              • "; - echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=bug"), $lang->my->bug) . "
              • "; - //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=team"), $lang->my->team) . "
              • "; - echo << -$("#{$tabID}tab").addClass('active'); - -EOT; - ?> -
              -
              - -
              -
              -
              - + + * @package my + * @version $Id$ + * @link http://www.zentao.net + */ +?> + + +
              +
              + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
              my->profile;?>
              user->account;?>account;?>
              user->realname;?>realname;?>
              user->nickname;?>nickname;?>
              user->commiter;?>commiter;?>
              user->join;?>join;?>
              user->visits;?>visits;?>
              user->ip;?>ip;?>
              user->last;?>last;?>
              + +
              +
              +
              +
              +
                + {$user->realname}"; + echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=task"), $lang->my->task) . "
              • "; + //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=todo"), $lang->my->todo) . "
              • "; + echo "
              • ". html::a($this->createLink('user', 'view', "account=$user->account&tabID=project"), $lang->my->myProject) . "
              • "; + //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=story"), $lang->my->story) . "
              • "; + echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=bug"), $lang->my->bug) . "
              • "; + //echo "
              • " . html::a($this->createLink('user', 'view', "account=$user->account&tabID=team"), $lang->my->team) . "
              • "; + echo << +$("#{$tabID}tab").addClass('active'); + +EOT; + ?> +
              +
              + +
              +
              +
              + diff --git a/www/index.php b/www/index.php index a93b800f7c..4fd7cf9d45 100644 --- a/www/index.php +++ b/www/index.php @@ -1,43 +1,43 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -/* Set the error reporting. */ -error_reporting(0); - -/* Start output buffer. */ -ob_start(); - -/* Load the framework. */ -include '../framework/router.class.php'; -include '../framework/control.class.php'; -include '../framework/model.class.php'; -include '../framework/helper.class.php'; - -/* Log the time and define the run mode. */ -$startTime = getTime(); - -/* Instance the app. */ -$app = router::createApp('pms', dirname(dirname(__FILE__))); - -/* Check the reqeust is getconfig or not. Check installed or not. */ -if(isset($_GET['mode']) and $_GET['mode'] == 'getconfig') die($app->exportConfig()); // -if(!isset($config->installed) or !$config->installed) die(header('location: install.php')); - -/* Run the app. */ -$common = $app->loadCommon(); -$app->parseRequest(); -$common->checkPriv(); -$app->loadModule(); - -/* Flush the buffer. */ -ob_end_flush(); + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +/* Set the error reporting. */ +error_reporting(0); + +/* Start output buffer. */ +ob_start(); + +/* Load the framework. */ +include '../framework/router.class.php'; +include '../framework/control.class.php'; +include '../framework/model.class.php'; +include '../framework/helper.class.php'; + +/* Log the time and define the run mode. */ +$startTime = getTime(); + +/* Instance the app. */ +$app = router::createApp('pms', dirname(dirname(__FILE__))); + +/* Check the reqeust is getconfig or not. Check installed or not. */ +if(isset($_GET['mode']) and $_GET['mode'] == 'getconfig') die($app->exportConfig()); // +if(!isset($config->installed) or !$config->installed) die(header('location: install.php')); + +/* Run the app. */ +$common = $app->loadCommon(); +$app->parseRequest(); +$common->checkPriv(); +$app->loadModule(); + +/* Flush the buffer. */ +ob_end_flush(); diff --git a/www/install.php b/www/install.php index 58f0aa9f71..3b62aebd26 100644 --- a/www/install.php +++ b/www/install.php @@ -1,38 +1,38 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -error_reporting(0); -session_start(); -define('IN_INSTALL', true); - -/* Load the framework. */ -include '../framework/router.class.php'; -include '../framework/control.class.php'; -include '../framework/model.class.php'; -include '../framework/helper.class.php'; - -/* Instance the app. */ -$app = router::createApp('pms', dirname(dirname(__FILE__))); - -/* Check installed or not. */ -if(!isset($_SESSION['installing']) and isset($config->installed) and $config->installed) die(header('location: index.php')); - -/* Reset the config params to make sure the install program will be lauched. */ -$config->set('requestType', 'GET'); -$config->set('debug', true); -$config->set('default.module', 'install'); -$app->setDebug(); - -/* During the installation, if the database params is setted, auto connect the db. */ -if(isset($config->installed) and $config->installed) $app->connectDB(); - -$app->parseRequest(); -$app->loadModule(); + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +error_reporting(0); +session_start(); +define('IN_INSTALL', true); + +/* Load the framework. */ +include '../framework/router.class.php'; +include '../framework/control.class.php'; +include '../framework/model.class.php'; +include '../framework/helper.class.php'; + +/* Instance the app. */ +$app = router::createApp('pms', dirname(dirname(__FILE__))); + +/* Check installed or not. */ +if(!isset($_SESSION['installing']) and isset($config->installed) and $config->installed) die(header('location: index.php')); + +/* Reset the config params to make sure the install program will be lauched. */ +$config->set('requestType', 'GET'); +$config->set('debug', true); +$config->set('default.module', 'install'); +$app->setDebug(); + +/* During the installation, if the database params is setted, auto connect the db. */ +if(isset($config->installed) and $config->installed) $app->connectDB(); + +$app->parseRequest(); +$app->loadModule(); diff --git a/www/upgrade.php b/www/upgrade.php index 95a76f3d8f..dc072abb61 100644 --- a/www/upgrade.php +++ b/www/upgrade.php @@ -1,37 +1,37 @@ - - * @package ZenTaoPMS - * @version $Id$ - * @link http://www.zentao.net - */ -error_reporting(0); - -/* Load the framework. */ -include '../framework/router.class.php'; -include '../framework/control.class.php'; -include '../framework/model.class.php'; -include '../framework/helper.class.php'; - -/* Instance the app. */ -$app = router::createApp('pms', dirname(dirname(__FILE__))); -$common = $app->loadCommon(); - -/* Reset the config params to make sure the install program will be lauched. */ -$config->set('requestType', 'GET'); -$config->set('debug', true); -$config->set('default.module', 'upgrade'); -$app->setDebug(); - -/* Check the installed version is the latest or not. */ -$config->installedVersion = $common->loadModel('setting')->getVersion(); -if(version_compare($config->version, $config->installedVersion) <= 0) die(header('location: index.php')); - -/* Run it. */ -$app->parseRequest(); -$common->checkUpgradeStatus(); -$app->loadModule(); + + * @package ZenTaoPMS + * @version $Id$ + * @link http://www.zentao.net + */ +error_reporting(0); + +/* Load the framework. */ +include '../framework/router.class.php'; +include '../framework/control.class.php'; +include '../framework/model.class.php'; +include '../framework/helper.class.php'; + +/* Instance the app. */ +$app = router::createApp('pms', dirname(dirname(__FILE__))); +$common = $app->loadCommon(); + +/* Reset the config params to make sure the install program will be lauched. */ +$config->set('requestType', 'GET'); +$config->set('debug', true); +$config->set('default.module', 'upgrade'); +$app->setDebug(); + +/* Check the installed version is the latest or not. */ +$config->installedVersion = $common->loadModel('setting')->getVersion(); +if(version_compare($config->version, $config->installedVersion) <= 0) die(header('location: index.php')); + +/* Run it. */ +$app->parseRequest(); +$common->checkUpgradeStatus(); +$app->loadModule();