From 7c96bd88eee0752b0fd936111777ac3f7dad87b7 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Mon, 3 Nov 2014 05:51:43 +0000 Subject: [PATCH] * finish task #2878. --- module/bug/control.php | 15 +++++ module/bug/model.php | 49 ++++++++++++++ module/bug/view/batchcreate.html.php | 44 +++++++++++-- module/common/lang/en.php | 1 + module/common/lang/zh-cn.php | 1 + module/file/config.php | 2 + module/file/control.php | 35 ++++++++++ module/file/lang/en.php | 6 ++ module/file/lang/zh-cn.php | 6 ++ module/file/model.php | 23 +++++++ module/file/view/uploadimages.html.php | 23 +++++++ module/story/control.php | 16 +++++ module/story/model.php | 90 +++++++++++++++++--------- module/story/view/batchcreate.html.php | 32 ++++++++- 14 files changed, 305 insertions(+), 38 deletions(-) create mode 100644 module/file/view/uploadimages.html.php diff --git a/module/bug/control.php b/module/bug/control.php index 7245ee065c..c06faa5778 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -381,6 +381,21 @@ class bug extends control $stories = $this->story->getProductStoryPairs($productID); } + if($this->session->bugImagesFile) + { + $extractPath = $this->session->bugImagesFile; + if(is_dir($extractPath)) + { + $titles = array(); + foreach(glob($extractPath . '/*') as $fileName) + { + $fileName = basename($fileName); + $titles[$fileName] = preg_replace('/^\d+_/', '', pathinfo($fileName, PATHINFO_FILENAME)); + } + $this->view->titles = $titles; + } + } + /* Remove the unused types. */ unset($this->lang->bug->typeList['designchange']); unset($this->lang->bug->typeList['newfeature']); diff --git a/module/bug/model.php b/module/bug/model.php index 73461ea179..7eddc501b3 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -117,6 +117,7 @@ class bugModel extends model $data->browsers[$i] = $browser; } + if(isset($data->uploadImage)) $this->loadModel('file'); for($i = 0; $i < $batchNum; $i++) { if(empty($data->title[$i])) continue; @@ -135,6 +136,35 @@ class bugModel extends model $bug->os = $data->oses[$i]; $bug->browser = $data->browsers[$i]; + if(!empty($data->uploadImage[$i])) + { + $fileName = htmlspecialchars_decode($data->uploadImage[$i]); + $realPath = $this->session->bugImagesFile . $fileName; + + $file = array(); + $file['extension'] = $this->file->getExtension($fileName); + $file['pathname'] = $this->file->setPathName($i, $file['extension']); + $file['title'] = str_replace(".{$file['extension']}", '', $fileName); + $file['size'] = filesize($realPath); + if(rename($realPath, $this->file->savePath . $file['pathname'])) + { + if(in_array($file['extension'], $this->config->file->imageExtensions)) + { + $file['addedBy'] = $this->app->user->account; + $file['addedDate'] = $now; + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + + $url = $this->file->webPath . $file['pathname']; + $bug->steps .= ''; + unset($file); + } + } + else + { + unset($file); + } + } + if(!empty($moduleOwners[$bug->module])) { $bug->assignedTo = $moduleOwners[$bug->module]; @@ -144,9 +174,28 @@ class bugModel extends model $this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec(); $bugID = $this->dao->lastInsertID(); + if(!empty($data->uploadImage[$i]) and !empty($file)) + { + $file['objectType'] = 'bug'; + $file['objectID'] = $bugID; + $file['addedBy'] = $this->app->user->account; + $file['addedDate'] = $now; + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + unset($file); + } + if(dao::isError()) die(js::error('bug#' . ($i+1) . dao::getError(true))); $actions[$bugID] = $this->action->create('bug', $bugID, 'Opened'); } + + /* Remove upload image file and session. */ + if(!empty($data->uploadImage) and $this->session->bugImagesFile) + { + $classFile = $this->app->loadClass('zfile'); + if(is_dir($this->session->bugImagesFile)) $classFile->removeDir($this->session->bugImagesFile); + unset($_SESSION['bugImagesFile']); + } + return $actions; } diff --git a/module/bug/view/batchcreate.html.php b/module/bug/view/batchcreate.html.php index 12fe2fc6bf..14b8268219 100644 --- a/module/bug/view/batchcreate.html.php +++ b/module/bug/view/batchcreate.html.php @@ -16,7 +16,10 @@
icons['bug']);?> icons['batchCreate']);?> bug->common . $lang->colon . $lang->bug->batchCreate;?> -
pasteText, "data-toggle='myModal'")?>
+
+ createLink('file', 'uploadImages', 'module=bug¶ms=' . helper::safe64Encode("productID=$productID&projectID=$projectID&moduleID=$moduleID")), $lang->uploadImages, '', "data-toggle='modal' data-type='iframe' class='btn' data-width='600px'")?> + pasteText, "data-toggle='myModal'")?> +
@@ -44,14 +47,47 @@ $lang->bug->osList += array('ditto' => $lang->bug->ditto); $lang->bug->browserList += array('ditto' => $lang->bug->ditto); ?> - bug->batchCreate; $i++):?> + + + $bugTitle):?> + + + + + + + + + + bug->typeList, $type, "class='form-control'");?> + bug->severityList, '', "class='form-control'");?> + bug->osList, $os, "class='form-control'");?> + + bug->browserList, $browser, "class='form-control'"); + echo html::hidden("uploadImage[$i]", $fileName); + ?> + + + + + + + bug->batchCreate; $i++):?> + diff --git a/module/common/lang/en.php b/module/common/lang/en.php index a430e7d08f..45b9ff3ae0 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -60,6 +60,7 @@ $lang->switchHelp = 'Toggle Help'; $lang->addFiles = 'Add Files'; $lang->files = 'Files '; $lang->pasteText = 'Paste text'; +$lang->uploadImages = 'Upload images '; $lang->timeout = 'Timed out, please check the network, or retry!'; $lang->repairTable = 'The table may be damaged, you can perform bin/checkdb on the command line to try to repair!'; $lang->duplicate = '%s has the same title'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 2674c6aae0..899c896b00 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -60,6 +60,7 @@ $lang->switchHelp = '切换帮助'; $lang->addFiles = '上传了附件 '; $lang->files = '附件 '; $lang->pasteText = '粘贴文本 '; +$lang->uploadImages = '多图上传 '; $lang->timeout = '连接超时,请检查网络环境,或重试!'; $lang->repairTable = '数据库表可能损坏,需要修复,可以在命令行执行bin目录下的checkdb尝试修复!'; $lang->duplicate = '已有相同标题的%s'; diff --git a/module/file/config.php b/module/file/config.php index 55333f611e..d6ba555602 100644 --- a/module/file/config.php +++ b/module/file/config.php @@ -3,3 +3,5 @@ $config->file->mimes['xml'] = 'text/xml'; $config->file->mimes['html'] = 'text/html'; $config->file->mimes['csv'] = 'text/csv'; $config->file->mimes['default'] = 'application/octet-stream'; + +$config->file->imageExtensions = array('jpeg', 'jpg', 'gif', 'png'); diff --git a/module/file/control.php b/module/file/control.php index 6fcbc1ffb7..c8fb502a3f 100644 --- a/module/file/control.php +++ b/module/file/control.php @@ -306,4 +306,39 @@ class file extends control echo $this->file->pasteImage($this->post->editor); } } + + /** + * Upload zip of Images. + * + * @param string $module + * @param string $params + * @access public + * @return void + */ + public function uploadImages($module, $params) + { + if($_FILES) + { + $file = $this->file->getUpload('file'); + $file = $file[0]; + + if(!$file) die(js::alert($this->lang->error->noData)); + if($file['extension'] != 'zip') die(js::alert($this->lang->file->errorSuffix)); + if($file['size'] == 0) die(js::alert($this->lang->file->errorFileUpload)); + + if(@move_uploaded_file($file['tmpname'], $this->file->savePath . $file['pathname'])) + { + $zipFile = $this->file->savePath . $file['pathname']; + $filePath = $this->file->extractZip($zipFile); + + unlink($zipFile); + if(!$filePath) die(js::alert($this->lang->file->errorExtract)); + + $this->session->set($module . 'ImagesFile', $filePath); + die(js::locate($this->createLink($module, 'batchCreate', helper::safe64Decode($params)), 'parent.parent')); + } + } + + $this->display(); + } } diff --git a/module/file/lang/en.php b/module/file/lang/en.php index f91a521ffc..15d762d919 100644 --- a/module/file/lang/en.php +++ b/module/file/lang/en.php @@ -25,3 +25,9 @@ $lang->file->errorCanNotWrite = "The directory '%s' is unwrita $lang->file->confirmDelete = " Are you sure to delete this file?"; $lang->file->errorFileSize = " The file size exceeds the limit, might not be able to upload!"; $lang->file->errorFileUpload = " Failed to upload files, file size may exceed the limit!"; +$lang->file->errorSuffix = 'Compressed packet format error, can only upload zip!'; +$lang->file->errorExtract = 'Decompression failure! The file may have been damaged'; +$lang->file->uploadImagesExplain = <<1. Upload file to contain pictures of zip compressed package, the program will take the file name as a title, as content with pictures, generating a record.

+

2. if the file name at the beginning contains 'digital+underline', generation of title will they ignore, for example: '01_test', the title is 'test'.

+EOD; diff --git a/module/file/lang/zh-cn.php b/module/file/lang/zh-cn.php index 7ef3c190dd..a967b8931d 100644 --- a/module/file/lang/zh-cn.php +++ b/module/file/lang/zh-cn.php @@ -25,3 +25,9 @@ $lang->file->errorCanNotWrite = "文件夹 '%s' 不可写,请 $lang->file->confirmDelete = " 您确定删除该附件吗?"; $lang->file->errorFileSize = " 文件大小已经超过限制,可能不能成功上传!"; $lang->file->errorFileUpload = " 文件上传失败,文件大小可能超出限制"; +$lang->file->errorSuffix = '压缩包格式错误,只能上传zip压缩包!'; +$lang->file->errorExtract = '解压缩失败!可能文件已经损坏'; +$lang->file->uploadImagesExplain = <<1、上传文件为包含图片的zip压缩包,程序会以文件名作为标题,以图片作为内容,生成一条记录。以方便创建。

+

2、如果文件名开头含有 数字+下划线,生成的标题会将他们忽略,例如:01_测试,生成的标题名是“测试”。

+EOD; diff --git a/module/file/model.php b/module/file/model.php index 860fc56333..70861f78fb 100644 --- a/module/file/model.php +++ b/module/file/model.php @@ -384,4 +384,27 @@ class fileModel extends model { return str_replace('""', '"', $matchs[1]) . str_replace(',', ',', $matchs[2]); } + + /** + * Extract zip. + * + * @param string $zipFile + * @access public + * @return string + */ + public function extractZip($zipFile) + { + $classFile = $this->app->loadClass('zfile'); + $parentPath = $this->app->getCacheRoot() . 'uploadimages/'; + if(!is_dir($parentPath)) mkdir($parentPath, 0777, true); + + $filePath = $parentPath . str_replace('.zip', '', basename($zipFile)) . '/'; + if(is_dir($filePath)) $classFile->removeDir($filePath); + + $this->app->loadClass('pclzip', true); + $zip = new pclzip($zipFile); + $files = $zip->listContent(); + if($zip->extract(PCLZIP_OPT_PATH, $filePath) == 0) return false; + return $filePath; + } } diff --git a/module/file/view/uploadimages.html.php b/module/file/view/uploadimages.html.php new file mode 100644 index 0000000000..6058c37445 --- /dev/null +++ b/module/file/view/uploadimages.html.php @@ -0,0 +1,23 @@ + + * @package file + * @version $Id$ + * @link http://www.zentao.net + */ +?> + +
+ + + + + + +
file->uploadImagesExplain?>
+
+ diff --git a/module/story/control.php b/module/story/control.php index 59de841e33..3bde39b232 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -222,6 +222,22 @@ class story extends control $title = ''; $spec = ''; + /* Process upload images. */ + if($this->session->storyImagesFile) + { + $extractPath = $this->session->storyImagesFile; + if(is_dir($extractPath)) + { + $titles = array(); + foreach(glob($extractPath . '/*') as $fileName) + { + $fileName = basename($fileName); + $titles[$fileName] = preg_replace('/^\d+_/', '', pathinfo($fileName, PATHINFO_FILENAME)); + } + $this->view->titles = $titles; + } + } + $moduleOptionMenu['same'] = $this->lang->story->same; $plans = $this->loadModel('productplan')->getPairs($productID, 'unexpired'); $plans['same'] = $this->lang->story->same; diff --git a/module/story/model.php b/module/story/model.php index 45311dadbb..f0034c6640 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -230,25 +230,24 @@ class storyModel extends model $stories->pri[$i] = (int)$pri; } + if(isset($stories->uploadImage)) $this->loadModel('file'); for($i = 0; $i < $batchNum; $i++) { if($stories->title[$i] != '') { - $data[$i] = new stdclass(); - $data[$i]->module = $stories->module[$i]; - $data[$i]->plan = $stories->plan[$i]; - $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; + $data = new stdclass(); + $data->module = $stories->module[$i]; + $data->plan = $stories->plan[$i]; + $data->title = $stories->title[$i]; + $data->pri = $stories->pri[$i] != '' ? $stories->pri[$i] : 0; + $data->estimate = $stories->estimate[$i] != '' ? $stories->estimate[$i] : 0; + $data->status = $stories->needReview[$i] == 0 ? 'active' : 'draft'; + $data->product = $productID; + $data->openedBy = $this->app->user->account; + $data->openedDate = $now; + $data->version = 1; - $this->dao->insert(TABLE_STORY) - ->data($data[$i]) - ->autoCheck() + $this->dao->insert(TABLE_STORY)->data($data)->autoCheck() ->batchCheck($this->config->story->create->requiredFields, 'notempty') ->exec(); if(dao::isError()) @@ -260,12 +259,43 @@ class storyModel extends model $storyID = $this->dao->lastInsertID(); $this->setStage($storyID); - $specData[$i] = new stdclass(); - $specData[$i]->story = $storyID; - $specData[$i]->version = 1; - $specData[$i]->title = $stories->title[$i]; - if($stories->spec[$i] != '') $specData[$i]->spec = nl2br($stories->spec[$i]); - $this->dao->insert(TABLE_STORYSPEC)->data($specData[$i])->exec(); + $specData = new stdclass(); + $specData->story = $storyID; + $specData->version = 1; + $specData->title = $stories->title[$i]; + if($stories->spec[$i] != '') $specData->spec = nl2br($stories->spec[$i]); + + if(!empty($stories->uploadImage[$i])) + { + $fileName = htmlspecialchars_decode($stories->uploadImage[$i]); + $realPath = $this->session->storyImagesFile . $fileName; + + $file = array(); + $file['extension'] = $this->file->getExtension($fileName); + $file['pathname'] = $this->file->setPathName($i, $file['extension']); + $file['title'] = str_replace(".{$file['extension']}", '', $fileName); + $file['size'] = filesize($realPath); + if(rename($realPath, $this->file->savePath . $file['pathname'])) + { + $file['addedBy'] = $this->app->user->account; + $file['addedDate'] = $now; + if(in_array($file['extension'], $this->config->file->imageExtensions)) + { + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + + $url = $this->file->webPath . $file['pathname']; + $specData->spec .= ''; + } + else + { + $file['objectType'] = 'story'; + $file['objectID'] = $storyID; + $this->dao->insert(TABLE_FILE)->data($file)->exec(); + } + } + } + + $this->dao->insert(TABLE_STORYSPEC)->data($specData)->exec(); $this->loadModel('action'); $actionID = $this->action->create('story', $storyID, 'Opened', ''); @@ -273,18 +303,16 @@ class storyModel extends model $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]); - } } + + /* Remove upload image file and session. */ + if(!empty($stories->uploadImage) and $this->session->storyImagesFile) + { + $classFile = $this->app->loadClass('zfile'); + if(is_dir($this->session->storyImagesFile)) $classFile->removeDir($this->session->storyImagesFile); + unset($_SESSION['storyImagesFile']); + } + return $mails; } diff --git a/module/story/view/batchcreate.html.php b/module/story/view/batchcreate.html.php index 879835c312..f4be9e4853 100644 --- a/module/story/view/batchcreate.html.php +++ b/module/story/view/batchcreate.html.php @@ -15,7 +15,10 @@
icons['story']);?> icons['batchCreate']);?> story->batchCreate;?> -
pasteText, "data-toggle='myModal'")?>
+
+ createLink('file', 'uploadImages', 'module=story¶ms=' . helper::safe64Encode("productID=$productID&moduleID=$moduleID")), $lang->uploadImages, '', "data-toggle='modal' data-type='iframe' class='btn' data-width='600px'")?> + pasteText, "data-toggle='myModal'")?> +
@@ -32,7 +35,9 @@ story->review;?> - story->batchCreate; $i++):?> + + + $storyTitle):?> @@ -41,9 +46,30 @@ + + + - + story->reviewList, 0, "class='form-control'"); + echo html::hidden("uploadImage[$i]", $fileName); + ?> + + + + + + story->batchCreate; $i++):?> + + + + + + + + + story->reviewList, 0, "class='form-control'");?>