* @package bug
* @version $Id: model.php 5079 2013-07-10 00:44:34Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
?>
loadModel('product')->setMenu($products, $productID, $branch, $moduleID, 'bug');
$selectHtml = $this->product->select($products, $productID, 'bug', 'browse', '', $branch, $moduleID, 'bug');
foreach($this->lang->bug->menu as $key => $menu)
{
if($this->config->global->flow != 'onlyTest')
{
$replace = ($key == 'product') ? $selectHtml : $productID;
}
else
{
if($key == 'product')
{
$replace = $selectHtml;
}
else
{
$replace = array();
$replace['productID'] = $productID;
$replace['branch'] = $branch;
$replace['param'] = $moduleID;
}
}
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', '')
->setDefault('deadline', '0000-00-00')
->setIF(strpos($this->config->bug->create->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline)
->setIF($this->post->assignedTo != '', 'assignedDate', $now)
->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
->stripTags($this->config->bug->editor->create['id'], $this->config->allowedTags)
->cleanInt('product, module, severity')
->join('openedBuild', ',')
->join('mailto', ',')
->remove('files, labels,uid,oldTaskID')
->get();
/* Check repeat bug. */
$result = $this->loadModel('common')->removeDuplicate('bug', $bug, "product={$bug->product}");
if($result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']);
$bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->create['id'], $this->post->uid);
$this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
if(!dao::isError())
{
$bugID = $this->dao->lastInsertID();
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
$this->file->saveUpload('bug', $bugID);
empty($bug->case) ? $this->loadModel('score')->create('bug', 'create', $bugID) : $this->loadModel('score')->create('bug', 'createFormCase', $bug->case);
return array('status' => 'created', 'id' => $bugID);
}
return false;
}
/**
* Batch create
*
* @param int $productID
* @access public
* @return void
*/
public function batchCreate($productID, $branch = 0)
{
$this->loadModel('action');
$branch = (int)$branch;
$now = helper::now();
$actions = array();
$data = fixer::input('post')->get();
$batchNum = count(reset($data));
$result = $this->loadModel('common')->removeDuplicate('bug', $data, "product={$productID}");
$data = $result['data'];
for($i = 0; $i < $batchNum; $i++)
{
if(!empty($data->title[$i]))
{
if(empty($data->modules[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->module)));
if(empty($data->openedBuilds[$i])) die(js::alert(sprintf($this->lang->error->notempty, $this->lang->bug->openedBuild)));
}
}
/* Get pairs(moduleID => moduleOwner) for bug. */
$stmt = $this->dbh->query($this->loadModel('tree')->buildMenuQuery($productID, 'bug', $startModuleID = 0, $branch));
$moduleOwners = array();
while($module = $stmt->fetch()) $moduleOwners[$module->id] = $module->owner;
$module = 0;
$project = 0;
$type = '';
$pri = 0;
$os = '';
$browser = '';
for($i = 0; $i < $batchNum; $i++)
{
if($data->modules[$i] != 'ditto') $module = (int)$data->modules[$i];
if($data->projects[$i] != 'ditto') $project = (int)$data->projects[$i];
if($data->types[$i] != 'ditto') $type = $data->types[$i];
if($data->pris[$i] != 'ditto') $pri = $data->pris[$i];
if($data->oses[$i] != 'ditto') $os = $data->oses[$i];
if($data->browsers[$i] != 'ditto') $browser = $data->browsers[$i];
$data->modules[$i] = (int)$module;
$data->projects[$i] = (int)$project;
$data->types[$i] = $type;
$data->pris[$i] = $pri;
$data->oses[$i] = $os;
$data->browsers[$i] = $browser;
}
if(isset($data->uploadImage)) $this->loadModel('file');
for($i = 0; $i < $batchNum; $i++)
{
if(empty($data->title[$i])) continue;
$bug = new stdClass();
$bug->openedBy = $this->app->user->account;
$bug->openedDate = $now;
$bug->product = $productID;
$bug->branch = $data->branches[$i];
$bug->module = $data->modules[$i];
$bug->project = $data->projects[$i];
$bug->openedBuild = implode(',', $data->openedBuilds[$i]);
$bug->color = $data->color[$i];
$bug->title = $data->title[$i];
$bug->steps = nl2br($data->stepses[$i]);
$bug->type = $data->types[$i];
$bug->pri = $data->pris[$i];
$bug->severity = $data->severities[$i];
$bug->os = $data->oses[$i];
$bug->browser = $data->browsers[$i];
$bug->keywords = $data->keywords[$i];
if(!empty($data->uploadImage[$i]))
{
$fileName = $data->uploadImage[$i];
$file = $this->session->bugImagesFile[$fileName];
$realPath = $file['realpath'];
unset($file['realpath']);
if(rename($realPath, $this->file->savePath . $this->file->getSaveName($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();
$fileID = $this->dao->lastInsertID();
$bug->steps .= '';
}
}
else
{
unset($file);
}
}
if(!empty($moduleOwners[$bug->module]))
{
$bug->assignedTo = $moduleOwners[$bug->module];
$bug->assignedDate = $now;
}
$this->dao->insert(TABLE_BUG)->data($bug)->autoCheck()->batchCheck($this->config->bug->create->requiredFields, 'notempty')->exec();
$bugID = $this->dao->lastInsertID();
if(!dao::isError()) $this->loadModel('score')->create('bug', 'create', $bugID);
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');
$file = current($_SESSION['bugImagesFile']);
$realPath = dirname($file['realpath']);
if(is_dir($realPath)) $classFile->removeDir($realPath);
unset($_SESSION['bugImagesFile']);
}
if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchCreate');
return $actions;
}
/**
* Get bugs.
*
* @param int $productID
* @param array $projects
* @param int $branch
* @param string $browseType
* @param int $moduleID
* @param int $queryID
* @param string $sort
* @param object $pager
* @access public
* @return array
*/
public function getBugs($productID, $projects, $branch, $browseType, $moduleID, $queryID, $sort, $pager)
{
/* Set modules and browse type. */
$modules = $moduleID ? $this->loadModel('tree')->getAllChildId($moduleID) : '0';
$browseType = ($browseType == 'bymodule' and $this->session->bugBrowseType and $this->session->bugBrowseType != 'bysearch') ? $this->session->bugBrowseType : $browseType;
/* Get bugs by browse type. */
$bugs = array();
if($browseType == 'all') $bugs = $this->getAllBugs($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'bymodule') $bugs = $this->getModuleBugs($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'assigntome') $bugs = $this->getByAssigntome($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'openedbyme') $bugs = $this->getByOpenedbyme($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'resolvedbyme') $bugs = $this->getByResolvedbyme($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'assigntonull') $bugs = $this->getByAssigntonull($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'unconfirmed') $bugs = $this->getUnconfirmed($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'unresolved') $bugs = $this->getByStatus($productID, $branch, $modules, $projects, 'unresolved', $sort, $pager);
elseif($browseType == 'unclosed') $bugs = $this->getByStatus($productID, $branch, $modules, $projects, 'unclosed', $sort, $pager);
elseif($browseType == 'toclosed') $bugs = $this->getByStatus($productID, $branch, $modules, $projects, 'toclosed', $sort, $pager);
elseif($browseType == 'longlifebugs') $bugs = $this->getByLonglifebugs($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'postponedbugs') $bugs = $this->getByPostponedbugs($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'needconfirm') $bugs = $this->getByNeedconfirm($productID, $branch, $modules, $projects, $sort, $pager);
elseif($browseType == 'bysearch') $bugs = $this->getBySearch($productID, $queryID, $sort, $pager, $branch);
elseif($browseType == 'overduebugs') $bugs = $this->getOverdueBugs($productID, $branch, $modules, $projects, $sort, $pager);
return $this->checkDelayBugs($bugs);
}
/**
* Check delay bug.
*
* @param array $bugs
* @access public
* @return array
*/
public function checkDelayBugs($bugs)
{
foreach ($bugs as $bug)
{
// Delayed or not?.
if($bug->deadline != '0000-00-00')
{
if(substr($bug->resolvedDate, 0, 10) != '0000-00-00')
{
$delay = helper::diffDate(substr($bug->resolvedDate, 0, 10), $bug->deadline);
}
elseif($bug->status == 'active')
{
$delay = helper::diffDate(helper::today(), $bug->deadline);
}
if(isset($delay) and $delay > 0) $bug->delay = $delay;
}
}
return $bugs;
}
/**
* Get bugs of a module.
*
* @param int $productID
* @param string|array $moduleIdList
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getModuleBugs($productID, $branch = 0, $moduleIdList = 0, $projects, $orderBy = 'id_desc', $pager = null)
{
return $this->dao->select('*')->from(TABLE_BUG)
->where('product')->eq((int)$productID)
->beginIF(!empty($branch))->andWhere('branch')->eq($branch)->fi()
->beginIF(!empty($moduleIdList))->andWhere('module')->in($moduleIdList)->fi()
->andWhere('project')->in(array_keys($projects))
->andWhere('deleted')->eq(0)
->orderBy($orderBy)->page($pager)->fetchAll();
}
/**
* Get bug list of a plan.
*
* @param int $planID
* @param string $status
* @param string $orderBy
* @param object $pager
* @access public
* @return void
*/
public function getPlanBugs($planID, $status = 'all', $orderBy = 'id_desc', $pager = null)
{
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where('plan')->eq((int)$planID)
->beginIF($status != 'all')->andWhere('status')->in($status)->fi()
->andWhere('deleted')->eq(0)
->orderBy($orderBy)->page($pager)->fetchAll('id');
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
return $bugs;
}
/**
* Get info of a bug.
*
* @param int $bugID
* @param bool $setImgSize
* @access public
* @return object
*/
public function getById($bugID, $setImgSize = false)
{
$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, t5.title AS planName')
->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')
->leftJoin(TABLE_PRODUCTPLAN)->alias('t5')->on('t1.plan = t5.id')
->where('t1.id')->eq((int)$bugID)->fetch();
if(!$bug) return false;
$bug = $this->loadModel('file')->replaceImgURL($bug, 'steps');
if($setImgSize) $bug->steps = $this->file->setImgSize($bug->steps);
foreach($bug as $key => $value) if(strpos($key, 'Date') !== false and !(int)substr($value, 0, 4)) $bug->$key = '';
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->toCases = array();
$toCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('`fromBug`')->eq($bugID)->fetchAll();
foreach($toCases as $toCase) $bug->toCases[$toCase->id] = $toCase->title;
$bug->files = $this->loadModel('file')->getByObject('bug', $bugID);
return $bug;
}
/**
* Get bug list.
*
* @param int|array|string $bugIDList
* @access public
* @return array
*/
public function getByList($bugIDList = 0)
{
return $this->dao->select('*')->from(TABLE_BUG)
->where('deleted')->eq(0)
->beginIF($bugIDList)->andWhere('id')->in($bugIDList)->fi()
->fetchAll('id');
}
/**
* getActiveBugs
*
* @param array $products
* @param int $projectID
* @param object $pager
* @access public
* @return array
*/
public function getActiveBugs($products, $branch, $projectID, $pager = null)
{
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($branch)->andWhere('branch')->in("0,$branch")->fi()
->beginIF(empty($products))->andWhere('project')->eq($projectID)->fi()
->andWhere('deleted')->eq(0)
->orderBy('id desc')
->page($pager)
->fetchAll();
}
/**
* get Active And Postponed Bugs
*
* @param int $products
* @param int $projectID
* @param int $pager
* @access public
* @return void
*/
public function getActiveAndPostponedBugs($products, $projectID, $pager = null)
{
return $this->dao->select('t1.*')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.product = t2.product')
->where("((t1.status = 'resolved' AND t1.resolution = 'postponed') OR (t1.status = 'active'))")
->andWhere('t1.toTask')->eq(0)
->andWhere('t1.toStory')->eq(0)
->beginIF(!empty($products))->andWhere('t1.product')->in($products)->fi()
->beginIF(empty($products))->andWhere('t1.project')->eq($projectID)->fi()
->andWhere('t2.project')->eq($projectID)
->andWhere("(t2.branch = '0' OR t1.branch = '0' OR t2.branch = t1.branch)")
->andWhere('t1.deleted')->eq(0)
->orderBy('id desc')
->page($pager)
->fetchAll();
}
/**
* Get module owner.
*
* @param int $moduleID
* @param int $productID
* @access public
* @return string
*/
public function getModuleOwner($moduleID, $productID)
{
$users = $this->loadModel('user')->getPairs('nodeleted');
if($moduleID)
{
$module = $this->dao->findByID($moduleID)->from(TABLE_MODULE)->fetch();
if($module->owner and isset($users[$module->owner])) return $module->owner;
$moduleIDList = explode(',', trim(str_replace(",$module->id,", ',', $module->path), ','));
krsort($moduleIDList);
if($moduleIDList)
{
$modules = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->in($moduleIDList)->andWhere('deleted')->eq(0)->fetchAll('id');
foreach($moduleIDList as $moduleID)
{
if(isset($modules[$moduleID]))
{
$module = $modules[$moduleID];
if($module->owner and isset($users[$module->owner])) return $module->owner;
}
}
}
}
$owner = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('QD');
return isset($users[$owner]) ? $owner : '';
}
/**
* Update a bug.
*
* @param int $bugID
* @access public
* @return void
*/
public function update($bugID)
{
$oldBug = $this->dao->select('*')->from(TABLE_BUG)->where('id')->eq((int)$bugID)->fetch();
if(!empty($_POST['lastEditedDate']) and $oldBug->lastEditedDate != $this->post->lastEditedDate)
{
dao::$errors[] = $this->lang->error->editedByOther;
return false;
}
$now = helper::now();
$bug = fixer::input('post')
->cleanInt('product,module,severity,project,story,task')
->stripTags($this->config->bug->editor->edit['id'], $this->config->allowedTags)
->setDefault('project,module,project,story,task,duplicateBug,branch', 0)
->setDefault('openedBuild', '')
->setDefault('plan', 0)
->setDefault('deadline', '0000-00-00')
->setDefault('resolvedDate', '0000-00-00 00:00:00')
->setIF(strpos($this->config->bug->edit->requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline)
->add('lastEditedBy', $this->app->user->account)
->add('lastEditedDate', $now)
->join('openedBuild', ',')
->join('mailto', ',')
->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))
->remove('comment,files,labels,uid')
->get();
$bug = $this->loadModel('file')->processImgURL($bug, $this->config->bug->editor->edit['id'], $this->post->uid);
$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())
{
if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bugID);
$this->file->updateObjectID($this->post->uid, $bugID, 'bug');
return common::createChanges($oldBug, $bug);
}
}
/**
* Batch update bugs.
*
* @access public
* @return array
*/
public function batchUpdate()
{
$bugs = array();
$allChanges = array();
$now = helper::now();
$data = fixer::input('post')->get();
$bugIDList = $this->post->bugIDList ? $this->post->bugIDList : array();
if(!empty($bugIDList))
{
/* Process the data if the value is 'ditto'. */
foreach($bugIDList as $bugID)
{
if($data->types[$bugID] == 'ditto') $data->types[$bugID] = isset($prev['type']) ? $prev['type'] : '';
if($data->severities[$bugID] == 'ditto') $data->severities[$bugID] = isset($prev['severity']) ? $prev['severity'] : 3;
if($data->pris[$bugID] == 'ditto') $data->pris[$bugID] = isset($prev['pri']) ? $prev['pri'] : 0;
if($data->branches[$bugID] == 'ditto') $data->branches[$bugID] = isset($prev['branch']) ? $prev['branch'] : 0;
if($data->plans[$bugID] == 'ditto') $data->plans[$bugID] = isset($prev['plan']) ? $prev['plan'] : '';
if($data->assignedTos[$bugID] == 'ditto') $data->assignedTos[$bugID] = isset($prev['assignedTo']) ? $prev['assignedTo'] : '';
if($data->resolvedBys[$bugID] == 'ditto') $data->resolvedBys[$bugID] = isset($prev['resolvedBy']) ? $prev['resolvedBy'] : '';
if($data->resolutions[$bugID] == 'ditto') $data->resolutions[$bugID] = isset($prev['resolution']) ? $prev['resolution'] : '';
if($data->os[$bugID] == 'ditto') $data->os[$bugID] = isset($prev['os']) ? $prev['os'] : '';
if($data->browsers[$bugID] == 'ditto') $data->browsers[$bugID] = isset($prev['browser']) ? $prev['browser'] : '';
$prev['type'] = $data->types[$bugID];
$prev['severity'] = $data->severities[$bugID];
$prev['pri'] = $data->pris[$bugID];
$prev['branch'] = $data->branches[$bugID];
$prev['plan'] = $data->plans[$bugID];
$prev['assignedTo'] = $data->assignedTos[$bugID];
$prev['resolvedBy'] = $data->resolvedBys[$bugID];
$prev['resolution'] = $data->resolutions[$bugID];
$prev['os'] = $data->os[$bugID];
$prev['browser'] = $data->browsers[$bugID];
}
/* Initialize bugs from the post data.*/
$oldBugs = $bugIDList ? $this->getByList($bugIDList) : array();
foreach($bugIDList as $bugID)
{
$oldBug = $oldBugs[$bugID];
$bug = new stdclass();
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$bug->type = $data->types[$bugID];
$bug->severity = $data->severities[$bugID];
$bug->pri = $data->pris[$bugID];
$bug->status = $data->statuses[$bugID];
$bug->color = $data->colors[$bugID];
$bug->title = $data->titles[$bugID];
$bug->plan = empty($data->plans[$bugID]) ? 0 : $data->plans[$bugID];
$bug->branch = empty($data->branches[$bugID]) ? 0 : $data->branches[$bugID];
$bug->assignedTo = $data->assignedTos[$bugID];
$bug->deadline = $data->deadlines[$bugID];
$bug->resolvedBy = $data->resolvedBys[$bugID];
$bug->keywords = $data->keywords[$bugID];
$bug->os = $data->os[$bugID];
$bug->browser = $data->browsers[$bugID];
$bug->resolution = $data->resolutions[$bugID];
$bug->duplicateBug = $data->duplicateBugs[$bugID] ? $data->duplicateBugs[$bugID] : $oldBug->duplicateBug;
if($bug->assignedTo != $oldBug->assignedTo) $bug->assignedDate = $now;
if(($bug->resolvedBy != '' or $bug->resolution != '') and $oldBug->status != 'resolved') $bug->resolvedDate = $now;
if($bug->resolution != '' and $bug->resolvedBy == '') $bug->resolvedBy = $this->app->user->account;
if($bug->resolution != '' and $bug->status != 'closed')
{
$bug->status = 'resolved';
$bug->confirmed = 1;
}
if($bug->resolution != '' and $bug->assignedTo == '')
{
$bug->assignedTo = $oldBug->openedBy;
$bug->assignedDate = $now;
}
$bugs[$bugID] = $bug;
unset($bug);
}
/* Update bugs. */
foreach($bugs as $bugID => $bug)
{
$oldBug = $oldBugs[$bugID];
$this->dao->update(TABLE_BUG)->data($bug)
->autoCheck()
->batchCheck($this->config->bug->edit->requiredFields, 'notempty')
->checkIF($bug->resolvedBy, 'resolution', 'notempty')
->checkIF($bug->resolution == 'duplicate', 'duplicateBug', 'notempty')
->where('id')->eq((int)$bugID)
->exec();
if(!dao::isError())
{
if(!empty($bug->resolvedBy)) $this->loadModel('score')->create('bug', 'resolve', $bugID);
$allChanges[$bugID] = common::createChanges($oldBug, $bug);
}
else
{
die(js::error('bug#' . $bugID . dao::getError(true)));
}
}
}
if(!dao::isError()) $this->loadModel('score')->create('ajax', 'batchEdit');
return $allChanges;
}
/**
* Batch active bugs.
*
* @access public
* @return array
*/
public function batchActivate()
{
$now = helper::now();
$data = fixer::input('post')->get();
$activateBugs = array();
$bugIDList = $data->bugIDList ? $data->bugIDList : array();
if(empty($bugIDList)) return $activateBugs;
foreach($bugIDList as $bugID)
{
if($data->statusList[$bugID] == 'active') continue;
$activateBugs[$bugID]['assignedTo'] = $data->assignedToList[$bugID];
$activateBugs[$bugID]['openedBuild'] = $data->openedBuildList[$bugID];
$activateBugs[$bugID]['comment'] = $data->commentList[$bugID];
$activateBugs[$bugID]['assignedDate'] = $now;
$activateBugs[$bugID]['resolution'] = '';
$activateBugs[$bugID]['status'] = 'active';
$activateBugs[$bugID]['resolvedDate'] = '0000-00-00';
$activateBugs[$bugID]['resolvedBy'] = '';
$activateBugs[$bugID]['resolvedBuild'] = '';
$activateBugs[$bugID]['closedBy'] = '';
$activateBugs[$bugID]['closedDate'] = '0000-00-00';
$activateBugs[$bugID]['duplicateBug'] = 0;
$activateBugs[$bugID]['toTask'] = 0;
$activateBugs[$bugID]['toStory'] = 0;
$activateBugs[$bugID]['lastEditedBy'] = $this->app->user->account;
$activateBugs[$bugID]['lastEditedDate'] = $now;
}
/* Update bugs. */
foreach($activateBugs as $bugID => $bug)
{
$this->dao->update(TABLE_BUG)->data($bug, $skipFields = 'comment')->autoCheck()->where('id')->eq((int)$bugID)->exec();
if(dao::isError()) die(js::error('bug#' . $bugID . dao::getError(true)));
$this->dao->update(TABLE_BUG)->set('activatedCount = activatedCount + 1')->where('id')->eq((int)$bugID)->exec();
}
return $activateBugs;
}
/**
* Assign a bug to a user again.
*
* @param int $bugID
* @access public
* @return string
*/
public function assign($bugID)
{
$now = helper::now();
$oldBug = $this->getById($bugID);
$bug = fixer::input('post')
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('lastEditedDate', $now)
->setDefault('assignedDate', $now)
->remove('comment,showModule')
->join('mailto', ',')
->get();
$this->dao->update(TABLE_BUG)
->data($bug)
->autoCheck()
->where('id')->eq($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();
$oldBug = $this->getById($bugID);
$bug = fixer::input('post')
->setDefault('confirmed', 1)
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('lastEditedDate', $now)
->setDefault('assignedDate', $now)
->remove('comment')
->join('mailto', ',')
->get();
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
if(!dao::isError())
{
$this->loadModel('score')->create('bug', 'confirmBug', $oldBug);
return common::createChanges($oldBug, $bug);
}
}
/**
* Batch confirm bugs.
*
* @param array $bugIDList
* @access public
* @return void
*/
public function batchConfirm($bugIDList)
{
$now = helper::now();
$bugs = $this->getByList($bugIDList);
foreach($bugIDList as $bugID)
{
if($bugs[$bugID]->confirmed) continue;
$bug = new stdclass();
$bug->assignedTo = $this->app->user->account;
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$bug->confirmed = 1;
$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)
{
if(strpos($this->config->bug->resolve->requiredFields, 'comment') !== false and !$this->post->comment)
{
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->comment);
return false;
}
$now = helper::now();
$oldBug = $this->getById($bugID);
$bug = fixer::input('post')
->add('resolvedBy', $this->app->user->account)
->add('status', 'resolved')
->add('confirmed', 1)
->add('assignedDate', $now)
->add('lastEditedBy', $this->app->user->account)
->add('lastEditedDate', $now)
->setDefault('resolvedDate', $now)
->setDefault('duplicateBug', 0)
->setDefault('assignedTo', $oldBug->openedBy)
->remove('comment,files,labels')
->get();
/* Can create build when resolve bug. */
if(isset($bug->createBuild))
{
if(empty($bug->buildName)) dao::$errors['buildName'][] = sprintf($this->lang->error->notempty, $this->lang->bug->placeholder->newBuildName);
if(empty($bug->buildProject)) dao::$errors['buildProject'][] = sprintf($this->lang->error->notempty, $this->lang->bug->project);
if(dao::isError()) return false;
$buildData = new stdclass();
$buildData->product = $oldBug->product;
$buildData->branch = $oldBug->branch;
$buildData->project = $bug->buildProject;
$buildData->name = $bug->buildName;
$buildData->date = date('Y-m-d');
$buildData->builder = $this->app->user->account;
$this->dao->insert(TABLE_BUILD)->data($buildData)->autoCheck()
->check('name', 'unique', "product = {$buildData->product} AND branch = {$buildData->branch} AND deleted = '0'")
->exec();
if(dao::isError()) return false;
$buildID = $this->dao->lastInsertID();
$this->loadModel('action')->create('build', $buildID, 'opened');
$bug->resolvedBuild = $buildID;
}
unset($bug->buildName);
unset($bug->createBuild);
unset($bug->buildProject);
if($bug->resolvedBuild != 'trunk') $bug->testtask = (int) $this->dao->select('id')->from(TABLE_TESTTASK)->where('build')->eq($bug->resolvedBuild)->orderBy('id_desc')->limit(1)->fetch('id');
$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();
if(!dao::isError()) $this->loadModel('score')->create('bug', 'resolve', $oldBug);
/* Link bug to build and release. */
$this->linkBugToBuild($bugID, $bug->resolvedBuild);
}
/**
* Batch change branch.
*
* @param array $bugIDList
* @param int $branchID
* @access public
* @return array
*/
public function batchChangeBranch($bugIDList, $branchID)
{
$now = helper::now();
$allChanges = array();
$oldBugs = $this->getByList($bugIDList);
foreach($bugIDList as $bugID)
{
$oldBug = $oldBugs[$bugID];
if($branchID == $oldBug->branch) continue;
$bug = new stdclass();
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$bug->branch = $branchID;
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
if(!dao::isError()) $allChanges[$bugID] = common::createChanges($oldBug, $bug);
}
return $allChanges;
}
/**
* Batch change the module of bug.
*
* @param array $bugIDList
* @param int $moduleID
* @access public
* @return array
*/
public function batchChangeModule($bugIDList, $moduleID)
{
$now = helper::now();
$allChanges = array();
$oldBugs = $this->getByList($bugIDList);
foreach($bugIDList as $bugID)
{
$oldBug = $oldBugs[$bugID];
if($moduleID == $oldBug->module) continue;
$bug = new stdclass();
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$bug->module = $moduleID;
$this->dao->update(TABLE_BUG)->data($bug)->autoCheck()->where('id')->eq((int)$bugID)->exec();
if(!dao::isError()) $allChanges[$bugID] = common::createChanges($oldBug, $bug);
}
return $allChanges;
}
/**
* Batch resolve bugs.
*
* @param array $bugIDList
* @param string $resolution
* @param string $resolvedBuild
* @access public
* @return void
*/
public function batchResolve($bugIDList, $resolution, $resolvedBuild)
{
$now = helper::now();
$bugs = $this->getByList($bugIDList);
$bug = reset($bugs);
$productID = $bug->product;
$users = $this->loadModel('user')->getPairs();
$product = $this->dao->findById($productID)->from(TABLE_PRODUCT)->fetch();
$stmt = $this->dao->query($this->loadModel('tree')->buildMenuQuery($productID, 'bug'));
$modules = array();
while($module = $stmt->fetch()) $modules[$module->id] = $module;
foreach($bugIDList as $i => $bugID)
{
$oldBug = $bugs[$bugID];
if($oldBug->resolution == 'fixed')
{
unset($bugIDList[$i]);
continue;
}
if($oldBug->status != 'active') continue;
$assignedTo = $oldBug->openedBy;
if(!isset($users[$assignedTo]))
{
$assignedTo = '';
$module = isset($modules[$oldBug->module]) ? $modules[$oldBug->module] : '';
while($module)
{
if($module->owner and isset($users[$module->owner]))
{
$assignedTo = $module->owner;
break;
}
$module = isset($modules[$module->parent]) ? $modules[$module->parent] : '';
}
if(empty($assignedTo)) $assignedTo = $product->QD;
}
$bug = new stdClass();
$bug->resolution = $resolution;
$bug->resolvedBuild = $resolution == 'fixed' ? $resolvedBuild : '';
$bug->resolvedBy = $this->app->user->account;
$bug->resolvedDate = $now;
$bug->status = 'resolved';
$bug->confirmed = 1;
$bug->assignedTo = $assignedTo;
$bug->assignedDate = $now;
$bug->lastEditedBy = $this->app->user->account;
$bug->lastEditedDate = $now;
$this->dao->update(TABLE_BUG)->data($bug)->where('id')->eq($bugID)->exec();
}
/* Link bug to build and release. */
$this->linkBugToBuild($bugIDList, $resolvedBuild);
return $bugIDList;
}
/**
* 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('toTask', 0)
->add('toStory', 0)
->add('lastEditedBy', $this->app->user->account)
->add('lastEditedDate', $now)
->add('activatedDate', $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)
{
$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();
}
/**
* Link related bugs.
*
* @param int $bugID
* @access public
* @return void
*/
public function linkBugs($bugID)
{
if($this->post->bugs == false) return;
$bug = $this->getById($bugID);
$bugs2Link = $this->post->bugs;
$bugs = implode(',', $bugs2Link) . ',' . trim($bug->linkBug, ',');
$this->dao->update(TABLE_BUG)->set('linkBug')->eq(trim($bugs, ','))->where('id')->eq($bugID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('bug', $bugID, 'linkRelatedBug', '', implode(',', $bugs2Link));
}
/**
* Get bugs to link.
*
* @param int $bugID
* @param string $browseType
* @param int $queryID
* @access public
* @return array
*/
public function getBugs2Link($bugID, $browseType = 'bySearch', $queryID)
{
if($browseType == 'bySearch')
{
$bug = $this->getById($bugID);
$bugs2Link = $this->getBySearch($bug->product, $queryID, 'id', null, $bug->branch);
foreach($bugs2Link as $key => $bug2Link)
{
if($bug2Link->id == $bugID) unset($bugs2Link[$key]);
if(in_array($bug2Link->id, explode(',', $bug->linkBug))) unset($bugs2Link[$key]);
}
return $bugs2Link;
}
else
{
return array();
}
}
/**
* Unlink related bug.
*
* @param int $bugID
* @param int $bug2Unlink
* @access public
* @return void
*/
public function unlinkBug($bugID, $bug2Unlink = 0)
{
$bug = $this->getById($bugID);
$bugs = explode(',', trim($bug->linkBug, ','));
foreach($bugs as $key => $bugId)
{
if($bugId == $bug2Unlink) unset($bugs[$key]);
}
$bugs = implode(',', $bugs);
$this->dao->update(TABLE_BUG)->set('linkBug')->eq($bugs)->where('id')->eq($bugID)->exec();
if(dao::isError()) die(js::error(dao::getError()));
$this->loadModel('action')->create('bug', $bugID, 'unlinkRelatedBug', '', $bug2Unlink);
}
/**
* Get linkBugs.
*
* @param int $bugID
* @access public
* @return array
*/
public function getLinkBugs($bugID)
{
$bug = $this->getById($bugID);
return $this->dao->select('id, title')->from(TABLE_BUG)->where('id')->in($bug->linkBug)->fetchPairs();
}
/**
* Build search form.
*
* @param int $productID
* @param array $products
* @param int $queryID
* @param string $actionURL
* @access public
* @return void
*/
public function buildSearchForm($productID, $products, $queryID, $actionURL)
{
$this->config->bug->search['actionURL'] = $actionURL;
$this->config->bug->search['queryID'] = $queryID;
$this->config->bug->search['params']['product']['values'] = array($productID => $products[$productID], 'all' => $this->lang->bug->allProduct);
$this->config->bug->search['params']['plan']['values'] = $this->loadModel('productplan')->getPairs($productID);
$this->config->bug->search['params']['module']['values'] = $this->loadModel('tree')->getOptionMenu($productID, $viewType = 'bug', $startModuleID = 0);
$this->config->bug->search['params']['project']['values'] = $this->product->getProjectPairs($productID);
$this->config->bug->search['params']['severity']['values'] = array(0 => '') + $this->lang->bug->severityList; //Fix bug #939.
$this->config->bug->search['params']['openedBuild']['values'] = $this->loadModel('build')->getProductBuildPairs($productID, 0, $params = '');
$this->config->bug->search['params']['resolvedBuild']['values'] = $this->config->bug->search['params']['openedBuild']['values'];
if($this->session->currentProductType == 'normal')
{
unset($this->config->bug->search['fields']['branch']);
unset($this->config->bug->search['params']['branch']);
}
else
{
$this->config->bug->search['fields']['branch'] = $this->lang->product->branch;
$this->config->bug->search['params']['branch']['values'] = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty') + array('all' => $this->lang->branch->all);
}
$this->loadModel('search')->setSearchParams($this->config->bug->search);
}
/**
* Process the openedBuild and resolvedBuild fields for bugs.
*
* @param array $bugs
* @access public
* @return array
*/
public function processBuildForBugs($bugs)
{
$productIdList = array();
foreach($bugs as $bug) $productIdList[$bug->id] = $bug->product;
$builds = $this->loadModel('build')->getProductBuildPairs(array_unique($productIdList), 0, $params = '');
/* Process the openedBuild and resolvedBuild fields. */
foreach($bugs as $key => $bug)
{
$openBuildIdList = explode(',', $bug->openedBuild);
$openedBuild = '';
foreach($openBuildIdList as $buildID)
{
$openedBuild .= isset($builds[$buildID]) ? $builds[$buildID] : $buildID;
$openedBuild .= ',';
}
$bug->openedBuild = rtrim($openedBuild, ',');
$bug->resolvedBuild = isset($builds[$bug->resolvedBuild]) ? $builds[$bug->resolvedBuild] : $bug->resolvedBuild;
}
return $bugs;
}
/**
* 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 user bugs.
*
* @param string $account
* @param string $type
* @param string $orderBy
* @param int $limit
* @param int $pager
* @access public
* @return void
*/
public function getUserBugs($account, $type = 'assignedTo', $orderBy = 'id_desc', $limit = 0, $pager = null)
{
if(!$this->loadModel('common')->checkField(TABLE_BUG, $type)) return array();
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where('deleted')->eq(0)
->beginIF($type != 'all')->andWhere("`$type`")->eq($account)->fi()
->orderBy($orderBy)
->beginIF($limit > 0)->limit($limit)->fi()
->page($pager)
->fetchAll();
return $bugs ? $bugs : array();
}
/**
* 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 int $build
* @param string $type
* @param int $param
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getProjectBugs($projectID, $build = 0, $type = '', $param = 0, $orderBy = 'id_desc', $pager = null)
{
if($type == 'bySearch')
{
$queryID = (int)$param;
$products = $this->loadModel('project')->getProducts($projectID);
if($this->session->projectBugQuery == false) $this->session->set('projectBugQuery', ' 1 = 1');
if($queryID)
{
$query = $this->loadModel('search')->getQuery($queryID);
if($query)
{
$this->session->set('projectBugQuery', $query->sql);
$this->session->set('projectBugForm', $query->form);
}
}
$allProduct = "`product` = 'all'";
$bugQuery = $this->session->projectBugQuery;
if(strpos($this->session->projectBugQuery, $allProduct) !== false)
{
$bugQuery = str_replace($allProduct, '1', $this->session->projectBugQuery);
}
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where($bugQuery)
->andWhere('project')->eq((int)$projectID)
->andWhere('deleted')->eq(0)
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
else
{
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where('deleted')->eq(0)
->beginIF(empty($build))->andWhere('project')->eq($projectID)->fi()
->beginIF($build)->andWhere("CONCAT(',', openedBuild, ',') like '%,$build,%'")->fi()
->orderBy($orderBy)->page($pager)->fetchAll();
}
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
return $bugs;
}
/**
* Get product left bugs.
*
* @param int $build
* @param int $productID
* @access public
* @return array
*/
public function getProductLeftBugs($build, $productID, $branch = 0)
{
$build = $this->dao->select('*')->from(TABLE_BUILD)->where('id')->eq($build)->fetch();
if(empty($build->project)) return array();
$project = $this->dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($build->project)->fetch();
$beforeBuilds = $this->dao->select('t1.id')->from(TABLE_BUILD)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project=t2.id')
->where('t1.product')->eq($productID)
->andWhere('t2.status')->ne('done')
->andWhere('t2.deleted')->eq(0)
->andWhere('t1.deleted')->eq(0)
->andWhere('t1.date')->lt($project->begin)
->fetchPairs('id', 'id');
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('deleted')->eq(0)
->andWhere('product')->eq($productID)
->andWhere('toStory')->eq(0)
->andWhere('openedDate')->ge($project->begin)
->andWhere('openedDate')->le($project->end)
->andWhere("(status = 'active' OR resolvedDate > '{$project->end}')")
->andWhere('openedBuild')->notin($beforeBuilds)
->beginIF($branch)->andWhere('branch')->in("0,$branch")->fi()
->fetchAll();
return $bugs;
}
/**
* get Product Bug Pairs
*
* @param int $productID
* @access public
* @return void
*/
public function getProductBugPairs($productID)
{
$bugs = array('' => '');
$data = $this->dao->select('id, title')->from(TABLE_BUG)
->where('product')->eq((int)$productID)
->andWhere('deleted')->eq(0)
->orderBy('id desc')
->fetchAll();
foreach($data as $bug)
{
$bugs[$bug->id] = $bug->id . ':' . $bug->title;
}
return $bugs;
}
/**
* Get bugs according to buildID and productID.
*
* @param int $buildID
* @param int $productID
* @access public
* @return object
*/
public function getReleaseBugs($buildID, $productID, $branch = 0)
{
$project = $this->dao->select('t1.id,t1.begin')->from(TABLE_PROJECT)->alias('t1')
->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.id = t2.project')
->where('t2.id')->eq($buildID)
->fetch();
$bugs = $this->dao->select('*')->from(TABLE_BUG)
->where('resolvedDate')->ge($project->begin)
->andWhere('resolution')->ne('postponed')
->andWhere('product')->eq($productID)
->beginIF($branch)->andWhere('branch')->in("0,$branch")->fi()
->andWhere("(project != '$project->id' OR (project = '$project->id' and openedDate < '$project->begin'))")
->andWhere('deleted')->eq(0)
->orderBy('openedDate ASC')
->fetchAll();
return $bugs;
}
/**
* Get bugs of a story.
*
* @param int $storyID
* @access public
* @return array
*/
public function getStoryBugs($storyID)
{
return $this->dao->select('id, title, pri, type, status, assignedTo, resolvedBy, resolution')
->from(TABLE_BUG)
->where('story')->eq((int)$storyID)
->andWhere('deleted')->eq(0)
->fetchAll('id');
}
/**
* Get case bugs.
*
* @param int $runID
* @param int $caseID
* @param int $version
* @access public
* @return void
*/
public function getCaseBugs($runID, $caseID = 0, $version = 0)
{
return $this->dao->select('*')->from(TABLE_BUG)
->where('1=1')
->beginIF($runID)->andWhere('`result`')->eq($runID)->fi()
->beginIF($runID == 0 and $caseID)->andWhere('`case`')->eq($caseID)->fi()
->beginIF($version)->andWhere('`caseVersion`')->eq($version)->fi()
->andWhere('deleted')->eq(0)
->fetchAll('id');
}
/**
* Get counts of some stories' bugs.
*
* @param array $stories
* @param int $projectID
* @access public
* @return int
*/
public function getStoryBugCounts($stories, $projectID = 0)
{
$bugCounts = $this->dao->select('story, COUNT(*) AS bugs')
->from(TABLE_BUG)
->where('story')->in($stories)
->andWhere('deleted')->eq(0)
->beginIF($projectID)->andWhere('project')->eq($projectID)->fi()
->groupBy('story')
->fetchPairs();
foreach($stories as $storyID) if(!isset($bugCounts[$storyID])) $bugCounts[$storyID] = 0;
return $bugCounts;
}
/**
* 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 = '';
$steps = zget($_POST, 'stepIDList', array());
$result = $this->dao->findById($resultID)->from(TABLE_TESTRESULT)->fetch();
if($caseID > 0)
{
$run = new stdclass();
$run->case = $this->loadModel('testcase')->getById($caseID, $result->version);
}
else
{
$run = $this->loadModel('testtask')->getRunById($result->run);
}
$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)) { $i = 1; foreach($steps as $stepId) { if(!isset($caseSteps[$stepId])) continue; $step = $caseSteps[$stepId]; $bugSteps .= $i . '. ' . $step->desc . "