/** * Set menu. * * @param array $projects * @param int $projectID * @param string $extra * @access public * @return void */ public function setMenu($projects, $projectID, $extra = '') { /* Check the privilege. */ $project = $this->getById($projectID); /* Unset story, bug, build and testtask if type is ops. */ if ($project and $project->type == 'ops') { unset($this->lang->project->menu->story); unset($this->lang->project->menu->bug); unset($this->lang->project->menu->build); unset($this->lang->project->menu->testtask); } if ($projects and !isset($projects[$projectID]) and !$this->checkPriv($project)) { echo js::alert($this->lang->project->accessDenied); die(js::locate('back')); } $moduleName = $this->app->getModuleName(); $methodName = $this->app->getMethodName(); if ($this->cookie->projectMode == 'noclosed' and $project->status == 'done') { setcookie('projectMode', 'all'); $this->cookie->projectMode = 'all'; } $selectHtml = $this->select($projects, $projectID, $moduleName, $methodName, $extra); foreach ($this->lang->project->menu as $key => $menu) { $replace = $key == 'list' ? $selectHtml : $projectID; common::setMenuVars($this->lang->project->menu, $key, $replace); } }
/** * Change password , if use default password ,go to change * * @access public * @return void */ public function changePassword() { if ($this->app->user->account == 'guest') { die(js::alert('guest') . js::locate('back')); } if (!empty($_POST)) { $password1 = $_POST['password1']; if (!$password1) { die(js::error('Please input password!')); } $isDefult = $this->dao->select('password')->from(TABLE_DEFAULTPASSWORD)->Where('password')->eq($this->post->password1)->fetchAll(); //如果用户使用默认密码则跳到修改密码界面 if ($isDefult) { die(js::error('Password can not in default list!') . js::locate($this->createLink('my', 'changePassword', 'type=forbidden'), 'parent')); } $this->user->updatePassword($this->app->user->id); if (dao::isError()) { die(js::error(dao::getError())); } die(js::locate($this->createLink('my', 'profile'), 'parent')); } $this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->changePassword; $this->view->position[] = $this->lang->my->changePassword; $this->view->user = $this->user->getById($this->app->user->id); $this->display(); }
public function test() { $pubuConfig = $this->pubu->getConfig(); $this->view->position[] = html::a(inlink('index'), $this->lang->pubu->common); $this->view->position[] = '测试'; $ping = $this->pubu->sendNotification($pubuConfig->webhook, array('type' => 'ping', "data" => array("hello" => "zentao"))); $this->view->ping = $ping; if (is_string($ping)) { echo js::alert($ping); die(js::locate('back')); } $this->display(); }
public function delete($type, $field) { $this->app->loadClass('infoextdao', $static = true); $table = $this->config->custom->typeToTable[$type]; $sql_query = 'ALTER TABLE ' . infoextdao::backquote($table) . ' ' . "DROP COLUMN " . infoextdao::backquote($this->config->customFieldPrefix . $field); try { $result = $this->app->dbh->query($sql_query); } catch (Exception $e) { //echo 'Message: ' .$e->getMessage(); echo js::alert(addslashes($sql_query)); echo js::alert($this->lang->custom->alterTableFailed); return false; } }
/** * 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->title = $this->lang->convert->setting; $this->view->source = $sourceName; $this->view->version = $version; $this->view->setting = $this->fetch('convert', $setFunc, "version={$version}"); $this->display(); }
/** * Custom * * @param string $module * @param string $field * @access public * @return void */ public function set($module = 'story', $field = 'priList') { if ($module == 'user' and $field == 'priList') { $field = 'roleList'; } $currentLang = $this->app->getClientLang(); $this->app->loadLang($module); $this->app->loadConfig('story'); $fieldList = $this->lang->{$module}->{$field}; if ($module == 'bug' and $field == 'typeList') { unset($fieldList['designchange']); unset($fieldList['newfeature']); unset($fieldList['trackthings']); } if (!empty($_POST)) { if ($module == 'story' && $field == 'review') { $this->loadModel('setting')->setItem('system.story.needReview', fixer::input('post')->get()->needReview); } else { $lang = $_POST['lang']; $this->custom->deleteItems("lang={$lang}&module={$module}§ion={$field}"); foreach ($_POST['keys'] as $index => $key) { $value = $_POST['values'][$index]; if (!$value or !$key) { continue; } $system = $_POST['systems'][$index]; /* the length of role is 20, check it when save. */ if ($module == 'user' and $field == 'roleList' and strlen($key) > 20) { die(js::alert($this->lang->custom->notice->userRole)); } $this->custom->setItem("{$lang}.{$module}.{$field}.{$key}.{$system}", $value); } } if (dao::isError()) { die(js::error(dao::getError())); } die(js::reload('parent')); } $this->view->title = $this->lang->custom->common . $this->lang->colon . $this->lang->{$module}->common; $this->view->position[] = $this->lang->custom->common; $this->view->position[] = $this->lang->{$module}->common; $this->view->needReview = $this->config->story->needReview; $this->view->fieldList = $fieldList; $this->view->dbFields = $this->custom->getItems("lang={$currentLang},all&module={$module}§ion={$field}"); $this->view->field = $field; $this->view->module = $module; $this->view->currentLang = $currentLang; $this->view->canAdd = strpos($this->config->custom->canAdd[$module], $field) !== false; $this->display(); }
/** * 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 : $projectID; common::setMenuVars($this->lang->project->menu, $key, $replace); } }
/** * Bind zentao. * * @access public * @return void */ public function bind() { if ($_POST) { $response = $this->admin->bindByAPI(); if ($response == 'success') { $this->loadModel('setting')->setItem('system.common.global.community', $this->post->account); echo js::alert($this->lang->admin->bind->success); die(js::locate(inlink('index'), 'parent')); } die($response); } $this->view->title = $this->lang->admin->bind->caption; $this->view->position[] = $this->lang->admin->bind->caption; $this->view->sn = $this->config->global->sn; $this->display(); }
/** * Create a task. * * @param int $projectID * @param int $storyID * @access public * @return void */ public function create($projectID = 0, $storyID = 0, $moduleID = 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'); $moduleOptionMenu = $this->tree->getOptionMenu($projectID, $viewType = 'task'); $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->view->moduleID = $moduleID; $this->view->moduleOptionMenu = $moduleOptionMenu; $this->display(); }
/** * Set menu. * * @param array $products * @param int $productID * @param string $extra * @access public * @return void */ public function setMenu($products, $productID, $extra = '') { /* Has access privilege?. */ if ($products and !isset($products[$productID]) and !$this->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 and story. */ if ($currentModule == 'story' and $currentMethod != 'create' and $currentMethod != 'batchcreate') { $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 : $productID; common::setMenuVars($this->lang->product->menu, $key, $replace); } }
/** * Bind user. * * @access public * @return object */ public function bind() { $data = fixer::input('post')->get(); if ($data->bindType == 'bind') { if (empty($data->bindPassword)) { die(js::alert($this->lang->sso->bindNoPassword)); } $password = md5($data->bindPassword); $user = $this->dao->select('*')->from(TABLE_USER)->where('account')->eq($data->bindUser)->andWhere('password')->eq($password)->andWhere('deleted')->eq('0')->fetch(); if (empty($user)) { die(js::alert($this->lang->sso->bindNoUser)); } $user->ranzhi = $this->session->ssoData->account; $this->dao->update(TABLE_USER)->set('ranzhi')->eq($user->ranzhi)->where('id')->eq($user->id)->exec(); } elseif ($data->bindType == 'add') { if (!$this->loadModel('user')->checkPassword()) { return; } $user = $this->dao->select('*')->from(TABLE_USER)->where('account')->eq($data->account)->fetch(); if ($user) { die(js::alert($this->lang->sso->bindHasAccount)); } if (isset($this->config->safe->mode) and $this->user->computePasswordStrength($data->password1) < $this->config->safe->mode) { dao::$errors['password1'][] = $this->lang->user->weakPassword; return false; } $user = new stdclass(); $user->account = $data->account; $user->password = md5($data->password1); $user->realname = $data->realname; $user->gender = isset($data->gender) ? $data->gender : ''; $user->email = $data->email; $user->ranzhi = $this->session->ssoData->account; $this->dao->insert(TABLE_USER)->data($user)->autoCheck()->batchCheck($this->config->user->create->requiredFields, 'notempty')->check('account', 'unique')->check('account', 'account')->checkIF($user->email != false, 'email', 'email')->exec(); } return $user; }
/** * Batch create * * @param int $productID * @access public * @return void */ public function batchCreate($productID, $branch = 0) { $this->loadModel('action'); $now = helper::now(); $actions = array(); $data = fixer::input('post')->get(); $batchNum = count(reset($data)); $result = $this->loadModel('common')->removeDuplicate('bug', $data, "product={$productID}&branch={$branch}"); $data = $result['data']; for ($i = 0; $i < $batchNum; $i++) { if (!empty($data->title[$i]) and 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 = ''; $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->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->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 = $branch; $bug->module = $data->modules[$i]; $bug->project = $data->projects[$i]; $bug->openedBuild = implode(',', $data->openedBuilds[$i]); $bug->title = $data->title[$i]; $bug->steps = nl2br($data->stepses[$i]); $bug->type = $data->types[$i]; $bug->severity = $data->severities[$i]; $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 .= '<img src="' . $url . '" alt="" />'; unset($file); } } 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 (!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; }
/** * Send test email. * * @access public * @return void */ public function test() { if (!$this->config->mail->turnon) { die(js::alert($this->lang->mail->needConfigure) . js::locate('back')); } if ($_POST) { $this->mail->send($this->post->to, $this->lang->mail->subject, $this->lang->mail->content, "", true); if ($this->mail->isError()) { $this->view->error = $this->mail->getError(); die($this->display()); } die(js::alert($this->lang->mail->successSended) . js::locate(inlink('test'))); } $this->view->title = $this->lang->mail->common . $this->lang->colon . $this->lang->mail->test; $this->view->position[] = html::a(inlink('index'), $this->lang->mail->common); $this->view->position[] = $this->lang->mail->test; $this->view->users = $this->dao->select('account, CONCAT(realname, " ", email) AS email')->from(TABLE_USER)->where('email')->ne('')->orderBy('account')->fetchPairs(); $this->display(); }
/** * Show import data * * @param int $productID * @access public * @return void */ public function showImport($productID) { if ($_POST) { $this->testcase->createFromImport($productID); die(js::locate(inlink('browse', "productID={$productID}"), 'parent')); } $this->testcase->setMenu($this->products, $productID); $file = $this->session->importFile; $caseLang = $this->lang->testcase; $caseConfig = $this->config->testcase; $fields = explode(',', $caseConfig->exportFields); $modules = $this->loadModel('tree')->getOptionMenu($productID, 'case'); $stories = $this->loadModel('story')->getProductStoryPairs($productID); foreach ($fields as $key => $fieldName) { $fieldName = trim($fieldName); $fields[$fieldName] = isset($caseLang->{$fieldName}) ? $caseLang->{$fieldName} : $fieldName; unset($fields[$key]); } $rows = $this->loadModel('file')->parseCSV($file); $header = $rows[0]; unset($rows[0]); foreach ($header as $title) { $field = array_search($title, $fields); if (!$field) { continue; } $columnKey[] = $field; } if (empty($columnKey)) { echo js::alert($this->lang->testcase->errorEncode); die(js::locate(inlink('browse', "productID={$productID}"))); } $endField = $field; $caseData = array(); $stepData = array(); foreach ($rows as $row => $data) { $case = new stdclass(); foreach ($columnKey as $key => $field) { if (!isset($data[$key])) { continue; } $cellValue = $data[$key]; if ($field == 'story') { $case->{$field} = 0; if (strrpos($cellValue, '(#') !== false) { $id = trim(substr($cellValue, strrpos($cellValue, '(#') + 2), ')'); $case->{$field} = $id; } } elseif ($field == 'module') { $case->{$field} = 0; if (strrpos($cellValue, '(#') !== false) { $id = trim(substr($cellValue, strrpos($cellValue, '(#') + 2), ')'); $case->{$field} = $id; } } elseif (in_array($field, $caseConfig->export->listFields)) { if ($field == 'stage') { $stages = explode("\n", $cellValue); foreach ($stages as $stage) { $case->stage[] = array_search($stage, $caseLang->{$field . 'List'}); } $case->stage = join(',', $case->stage); } else { $case->{$field} = array_search($cellValue, $caseLang->{$field . 'List'}); } } elseif ($field != 'stepDesc' and $field != 'stepExpect') { $case->{$field} = $cellValue; } else { $steps = explode("\n", $cellValue); $stepKey = str_replace('step', '', strtolower($field)); $caseStep = array(); foreach ($steps as $step) { $step = trim($step); if (empty($step)) { continue; } if (preg_match('/^([0-9]+)([.、]{1})/U', $step, $out)) { $num = $out[1]; $sign = $out[2]; $signbit = $sign == '.' ? 1 : 3; $step = trim(substr($step, strpos($step, $sign) + $signbit)); if (!empty($step)) { $caseStep[$num] = $step; } } elseif (isset($num)) { $caseStep[$num] .= "\n" . $step; } else { if ($field == 'stepDesc') { $num = 1; $caseStep[$num] = $step; } if ($field == 'stepExpect' and isset($stepData[$row]['desc'])) { end($stepData[$row]['desc']); $num = key($stepData[$row]['desc']); $caseStep[$num] = $step; } } } unset($num); unset($sign); $stepData[$row][$stepKey] = $caseStep; } } $caseData[$row] = $case; unset($case); } if (empty($caseData)) { echo js::alert($this->lang->error->noData); die(js::locate($this->createLink('testcase', 'browse'))); } $this->view->title = $this->lang->testcase->common . $this->lang->colon . $this->lang->testcase->showImport; $this->view->position[] = $this->lang->testcase->showImport; $this->view->stories = $stories; $this->view->modules = $modules; $this->view->cases = $this->dao->select('id, module, story')->from(TABLE_CASE)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetchAll('id'); $this->view->caseData = $caseData; $this->view->stepData = $stepData; $this->view->productID = $productID; $this->view->product = $this->products[$productID]; $this->display(); }
/** * View a doc. * * @param int $docID * @access public * @return void */ public function view($docID) { /* Get doc. */ $doc = $this->doc->getById($docID, true); if (!$doc) { die(js::error($this->lang->notFound) . js::locate('back')); } /* Check priv when lib is product or project. */ $systemLib = ($doc->lib == 'project' or $doc->lib == 'product') ? $doc->lib : ''; if ($systemLib and $doc->{$systemLib} and !$this->{$systemLib}->checkPriv($this->{$systemLib}->getById($doc->{$systemLib}))) { 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->title = "DOC #{$doc->id} {$doc->title} - " . $this->libs[$doc->lib]; $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,noletter'); $this->view->preAndNext = $this->loadModel('common')->getPreAndNextObject('doc', $docID); $this->view->keTableCSS = $this->doc->extractKETableCSS($doc->content); $this->display(); }
/** * 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; }
/** * Batch edit user. * * @access public * @return void */ public function batchEdit() { if (empty($_POST['verifyPassword']) or md5($this->post->verifyPassword) != $this->app->user->password) { die(js::alert($this->lang->user->error->verifyPassword)); } $oldUsers = $this->dao->select('id, account')->from(TABLE_USER)->where('id')->in(array_keys($this->post->account))->fetchPairs('id', 'account'); $accountGroup = $this->dao->select('id, account')->from(TABLE_USER)->where('account')->in($this->post->account)->fetchGroup('account', 'id'); $accounts = array(); foreach ($this->post->account as $id => $account) { $users[$id]['account'] = $account; $users[$id]['realname'] = $this->post->realname[$id]; $users[$id]['commiter'] = $this->post->commiter[$id]; $users[$id]['email'] = $this->post->email[$id]; $users[$id]['join'] = $this->post->join[$id]; $users[$id]['dept'] = $this->post->dept[$id] == 'ditto' ? isset($prev['dept']) ? $prev['dept'] : 0 : $this->post->dept[$id]; $users[$id]['role'] = $this->post->role[$id] == 'ditto' ? isset($prev['role']) ? $prev['role'] : 0 : $this->post->role[$id]; if (isset($accountGroup[$account]) and count($accountGroup[$account]) > 1) { die(js::error(sprintf($this->lang->user->error->accountDupl, $id))); } if (in_array($account, $accounts)) { die(js::error(sprintf($this->lang->user->error->accountDupl, $id))); } if (!validater::checkAccount($users[$id]['account'])) { die(js::error(sprintf($this->lang->user->error->account, $id))); } if ($users[$id]['realname'] == '') { die(js::error(sprintf($this->lang->user->error->realname, $id))); } if ($users[$id]['email'] and !validater::checkEmail($users[$id]['email'])) { die(js::error(sprintf($this->lang->user->error->mail, $id))); } if (empty($users[$id]['role'])) { die(js::error(sprintf($this->lang->user->error->role, $id))); } $accounts[$id] = $account; $prev['dept'] = $users[$id]['dept']; $prev['role'] = $users[$id]['role']; } foreach ($users as $id => $user) { $this->dao->update(TABLE_USER)->data($user)->where('id')->eq((int) $id)->exec(); if ($user['account'] != $oldUsers[$id]) { $oldAccount = $oldUsers[$id]; $this->dao->update(TABLE_USERGROUP)->set('account')->eq($user['account'])->where('account')->eq($oldAccount)->exec(); if (strpos($this->app->company->admins, ',' . $oldAccount . ',') !== false) { $admins = str_replace(',' . $oldAccount . ',', ',' . $user['account'] . ',', $this->app->company->admins); $this->dao->update(TABLE_COMPANY)->set('admins')->eq($admins)->where('id')->eq($this->app->company->id)->exec(); } if (!dao::isError() and $this->app->user->account == $oldAccount) { $this->app->user->account = $users['account']; } } } }
/** * Link stories to a project. * * @param int $projectID * @access public * @return void */ public function linkStory($projectID = 0, $browseType = '', $param = 0) { $this->loadModel('story'); $this->loadModel('product'); /* 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)); } $queryID = $browseType == 'bySearch' ? (int) $param : 0; /* Build search form. */ unset($this->config->product->search['fields']['module']); $this->config->product->search['actionURL'] = $this->createLink('project', 'linkStory', "projectID={$projectID}&browseType=bySearch&queryID=myQueryID"); $this->config->product->search['queryID'] = $queryID; $this->config->product->search['params']['product']['values'] = $products + array('all' => $this->lang->product->allProductsOfProject); $this->config->product->search['params']['plan']['values'] = $this->loadModel('productplan')->getForProducts($products); unset($this->lang->story->statusList['draft']); $this->config->product->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => $this->lang->story->statusList); $this->loadModel('search')->setSearchParams($this->config->product->search); $title = $project->name . $this->lang->colon . $this->lang->project->linkStory; $position[] = html::a($browseLink, $project->name); $position[] = $this->lang->project->linkStory; if ($browseType == 'bySearch') { $allStories = $this->story->getBySearch('', $queryID, 'id', null, $projectID); } else { $allStories = $this->story->getProductStories(array_keys($products), $moduleID = '0', $status = 'active'); } $prjStories = $this->story->getProjectStoryPairs($projectID); $this->view->title = $title; $this->view->position = $position; $this->view->project = $project; $this->view->products = $products; $this->view->allStories = $allStories; $this->view->prjStories = $prjStories; $this->view->browseType = $browseType; $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->display(); }
/** * Create from import * * @param int $productID * @access public * @return void */ public function createFromImport($productID) { $this->loadModel('action'); $this->loadModel('story'); $this->loadModel('file'); $now = helper::now(); $data = fixer::input('post')->get(); if (!empty($_POST['id'])) { $oldSteps = $this->dao->select('t2.*')->from(TABLE_CASE)->alias('t1')->leftJoin(TABLE_CASESTEP)->alias('t2')->on('t1.id = t2.case')->where('t1.id')->in($_POST['id'])->andWhere('t1.product')->eq($productID)->andWhere('t1.version=t2.version')->orderBy('t2.id')->fetchGroup('case'); $oldCases = $this->dao->select('*')->from(TABLE_CASE)->where('id')->in($_POST['id'])->fetchAll('id'); } $cases = array(); foreach ($data->product as $key => $product) { $caseData = new stdclass(); $caseData->product = $product; $caseData->module = $data->module[$key]; $caseData->story = (int) $data->story[$key]; $caseData->title = $data->title[$key]; $caseData->pri = (int) $data->pri[$key]; $caseData->type = $data->type[$key]; $caseData->status = $data->status[$key]; $caseData->stage = join(',', $data->stage[$key]); $caseData->frequency = 1; $caseData->precondition = $data->precondition[$key]; if (isset($this->config->testcase->create->requiredFields)) { $requiredFields = explode(',', $this->config->testcase->create->requiredFields); foreach ($requiredFields as $requiredField) { $requiredField = trim($requiredField); if (empty($caseData->{$requiredField})) { die(js::alert(sprintf($this->lang->testcase->noRequire, $key, $this->lang->testcase->{$requiredField}))); } } } $cases[$key] = $caseData; } foreach ($cases as $key => $caseData) { if (!empty($_POST['id'][$key])) { $caseID = $data->id[$key]; $stepChanged = false; $steps = array(); $oldStep = isset($oldSteps[$caseID]) ? $oldSteps[$caseID] : array(); $oldCase = $oldCases[$caseID]; /* Remove the empty setps in post. */ $steps = array(); if (isset($_POST['desc'][$key])) { foreach ($this->post->desc[$key] as $id => $desc) { $desc = trim($desc); if (empty($desc)) { continue; } $step = new stdclass(); $step->desc = $desc; $step->expect = trim($this->post->expect[$key][$id]); $steps[] = $step; } } /* If step count changed, case changed. */ if (!$oldStep != !$steps or count($oldStep) != count($steps)) { $stepChanged = true; } else { /* Compare every step. */ foreach ($oldStep as $id => $oldStep) { if (trim($oldStep->desc) != trim($steps[$id]->desc) or trim($oldStep->expect) != $steps[$id]->expect) { $stepChanged = true; break; } } } $version = $stepChanged ? $oldCase->version + 1 : $oldCase->version; $caseData->version = $version; $changes = common::createChanges($oldCase, $caseData); if (!$changes and !$stepChanged) { continue; } if ($changes or $stepChanged) { $caseData->lastEditedBy = $this->app->user->account; $caseData->lastEditedDate = $now; $this->dao->update(TABLE_CASE)->data($caseData)->where('id')->eq($caseID)->autoCheck()->exec(); if ($stepChanged) { foreach ($steps as $id => $step) { $step = (array) $step; if (empty($step['desc'])) { continue; } $stepData = new stdclass(); $stepData->case = $caseID; $stepData->version = $version; $stepData->desc = htmlspecialchars($step['desc']); $stepData->expect = htmlspecialchars($step['expect']); $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec(); } } $oldCase->steps = $this->joinStep($oldStep); $caseData->steps = $this->joinStep($steps); $changes = common::createChanges($oldCase, $caseData); $actionID = $this->action->create('case', $caseID, 'Edited'); $this->action->logHistory($actionID, $changes); } } else { $caseData->version = 1; $caseData->openedBy = $this->app->user->account; $caseData->openedDate = $now; $this->dao->insert(TABLE_CASE)->data($caseData)->autoCheck()->exec(); if (!dao::isError()) { $caseID = $this->dao->lastInsertID(); foreach ($this->post->desc[$key] as $id => $desc) { $desc = trim($desc); if (empty($desc)) { continue; } $stepData = new stdclass(); $stepData->case = $caseID; $stepData->version = 1; $stepData->desc = htmlspecialchars($desc); $stepData->expect = htmlspecialchars($this->post->expect[$key][$id]); $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec(); } $this->action->create('case', $caseID, 'Opened'); } } } unlink($this->session->importFile); unset($_SESSION['importFile']); }
/** * Delete * * @param string $fileName * @param string $confirm * @access public * @return void */ public function delete($fileName, $confirm = 'no') { if ($confirm == 'no') { die(js::confirm($this->lang->backup->confirmDelete, inlink('delete', "fileName={$fileName}&confirm=yes"))); } /* Delete database file. */ if (file_exists($this->backupPath . $fileName . '.sql.php') and !unlink($this->backupPath . $fileName . '.sql.php')) { die(js::alert(sprintf($this->lang->backup->error->noDelete, $this->backupPath . $fileName . '.sql.php'))); } /* Delete attatchments file. */ if (file_exists($this->backupPath . $fileName . '.file.zip.php') and !unlink($this->backupPath . $fileName . '.file.zip.php')) { die(js::alert(sprintf($this->lang->backup->error->noDelete, $this->backupPath . $fileName . '.file.zip.php'))); } die(js::reload('parent')); }
/** * Step4: create admin password and set the version. * * @access public * @return array */ public function step4() { if (!empty($_POST)) { $this->install->createAdmin(); if (dao::isError()) { die(js::error(dao::getError())); } if ($this->post->importDemoData) { $this->install->importDemoData(); } if (dao::isError()) { echo js::alert($this->lang->install->errorImportDemoData); } $this->loadModel('setting')->updateVersion($this->config->version); die(js::locate(inlink('step5'))); } if (!isset($this->config->installed) or !$this->config->installed) { $this->view->title = $this->lang->install->errorNotSaveConfig; $this->view->error = $this->lang->install->errorNotSaveConfig; $this->display(); } else { $this->view->title = $this->lang->install->setAdmin; $this->display(); } }
/** * Confirm clear data. * * @param string $confirm ''|no|yes * @access public * @return void */ public function clearData($confirm = '') { if ($confirm == '') { $this->display(); } if ($confirm == 'no') { die(js::confirm($this->lang->admin->confirmClearData, inlink('clearData', "confirm=yes"))); } elseif ($confirm == 'yes') { $result = $this->admin->clearData(); if ($result) { die(js::alert($this->lang->admin->clearDataSucceed)); } die(js::alert($this->lang->admin->clearDataFailed)); } }
/** * Edit a product. * * @param int $productID * @access public * @return void */ public function edit($productID) { $categories = $this->loadModel('tree')->getOptionMenu('product', 0, $removeRoot = true); if (empty($categories)) { die(js::alert($this->lang->tree->noCategories) . js::locate($this->createLink('tree', 'browse', 'type=product'))); } if ($_POST) { $this->product->update($productID); if (dao::isError()) { $this->send(array('result' => 'fail', 'message' => dao::getError())); } $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('admin'))); } $product = $this->product->getByID($productID); if (empty($product->attributes)) { $attribute = new stdclass(); $attribute->order = 0; $attribute->label = ''; $attribute->value = ''; $product->attributes = array($attribute); } $this->view->title = $this->lang->product->edit; $this->view->product = $product; $this->view->categories = $categories; $this->display(); }
/** * 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')); } }
/** * Manage contacts. * * @param int $listID * @access public * @return void */ public function manageContacts($listID = 0) { $lists = $this->user->getContactLists($this->app->user->account); /* If set $mode, need to update database. */ if ($this->post->mode) { /* The mode is new: append or new a list. */ if ($this->post->mode == 'new') { if ($this->post->list2Append) { $this->user->append2ContactList($this->post->list2Append, $this->post->users); die(js::locate(inlink('manageContacts', "listID={$this->post->list2Append}"), 'parent')); } elseif ($this->post->newList) { $listID = $this->user->createContactList($this->post->newList, $this->post->users); die(js::locate(inlink('manageContacts', "listID={$listID}"), 'parent')); } } elseif ($this->post->mode == 'edit') { $this->user->updateContactList($this->post->listID, $this->post->listName, $this->post->users); die(js::locate(inlink('manageContacts', "listID={$this->post->listID}"), 'parent')); } } if ($this->post->users) { $mode = 'new'; $users = $this->user->getContactUserPairs($this->post->users); } else { $mode = 'edit'; $listID = $listID ? $listID : key($lists); if (!$listID) { die(js::alert($this->lang->user->contacts->noListYet) . js::locate($this->createLink('company', 'browse'), 'parent')); } $list = $this->user->getContactListByID($listID); $users = explode(',', $list->userList); $users = $this->user->getContactUserPairs($users); $this->view->list = $list; } $this->view->title = $this->lang->company->common . $this->lang->colon . $this->lang->user->manageContacts; $this->view->position[] = $this->lang->company->common; $this->view->position[] = $this->lang->user->manageContacts; $this->view->lists = $this->user->getContactLists($this->app->user->account); $this->view->users = $users; $this->view->listID = $listID; $this->view->mode = $mode; $this->display(); }
/** * Manage privleges of a group. * * @param int $groupID * @access public * @return void */ public function managePriv($type = 'byGroup', $param = 0, $menu = '', $version = '') { if ($type == 'byGroup') { $groupID = $param; } $this->view->type = $type; foreach ($this->lang->resource as $moduleName => $action) { if ($this->group->checkMenuModule($menu, $moduleName) or $type != 'byGroup') { $this->app->loadLang($moduleName); } } if (!empty($_POST)) { if ($type == 'byGroup') { $result = $this->group->updatePrivByGroup($groupID, $menu, $version); } if ($type == 'byModule') { $result = $this->group->updatePrivByModule(); } print js::alert($result ? $this->lang->group->successSaved : $this->lang->group->errorNotSaved); exit; } if ($type == 'byGroup') { $this->group->sortResource(); $group = $this->group->getById($groupID); $groupPrivs = $this->group->getPrivs($groupID); $this->view->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; /* Join changelog when be equal or greater than this version.*/ $realVersion = str_replace('_', '.', $version); $changelog = array(); foreach ($this->lang->changelog as $currentVersion => $currentChangeLog) { if (version_compare($currentVersion, $realVersion, '>=')) { $changelog[] = join($currentChangeLog, ','); } } $this->view->group = $group; $this->view->changelogs = ',' . join($changelog, ',') . ','; $this->view->groupPrivs = $groupPrivs; $this->view->groupID = $groupID; $this->view->menu = $menu; $this->view->version = $version; } elseif ($type == 'byModule') { $this->group->sortResource(); $this->view->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(); }
/** * 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); $this->view->title = $this->lang->my->common . $this->lang->colon . $this->lang->my->profile; $this->view->position[] = $this->lang->my->profile; $this->view->user = $user; $this->view->groups = $this->loadModel('group')->getByAccount($this->app->user->account); $this->view->deptPath = $this->dept->getParents($user->dept); $this->display(); }
/** * Review a story. * * @param int $sqlID * @access public * @return bool */ public function review($sqlID) { 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)); } $oldSql = $this->dao->findById($sqlID)->from(TABLE_SQLREVIEW)->fetch(); $now = helper::now(); $date = helper::today(); $sql = 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 $oldSql->status == 'draft', 'status', 'active')->setIF($this->post->result == 'pass' and $oldSql->status == 'changed', 'status', 'active')->setIF($this->post->result == 'pass' and $oldSql->stage == 'wait', 'stage', 'passed')->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')->get(); $this->dao->update(TABLE_SQLREVIEW)->data($sql)->autoCheck()->batchCheck($this->config->story->review->requiredFields, 'notempty')->checkIF($this->post->result == 'reject', 'closedReason', 'notempty')->where('id')->eq($sqlID)->exec(); $this->setStage($sqlID); return true; }
/** * Undelete a record. * * @param int $actionID * @access public * @return void */ public function undelete($actionID) { $action = $this->getById($actionID); if ($action->action != 'deleted') { return; } if ($action->objectType == 'product') { $product = $this->dao->select('name,code')->from(TABLE_PRODUCT)->where('id')->eq($action->objectID)->fetch(); $count = $this->dao->select('COUNT(*) AS count')->from(TABLE_PRODUCT)->where('name')->eq($product->name)->orWhere('code')->eq($product->code)->fetch('count'); if ($count > 0) { echo js::alert(sprintf($this->lang->action->needEdit, $this->lang->action->objectTypes['product'])); die(js::locate(helper::createLink('product', 'edit', "productID={$action->objectID}&action=undelete&extra={$actionID}"), 'parent')); } } elseif ($action->objectType == 'project') { $project = $this->dao->select('name,code')->from(TABLE_PROJECT)->where('id')->eq($action->objectID)->fetch(); $count = $this->dao->select('COUNT(*) AS count')->from(TABLE_PROJECT)->where('name')->eq($project->name)->orWhere('code')->eq($project->code)->fetch('count'); if ($count > 0) { echo js::alert(sprintf($this->lang->action->needEdit, $this->lang->action->objectTypes['project'])); die(js::locate(helper::createLink('project', 'edit', "projectID={$action->objectID}&action=undelete&extra={$actionID}"), 'parent')); } } /* Update deleted field in object table. */ $table = $this->config->objectTables[$action->objectType]; $this->dao->update($table)->set('deleted')->eq(0)->where('id')->eq($action->objectID)->exec(); /* Update action record in action table. */ $this->dao->update(TABLE_ACTION)->set('extra')->eq(ACTIONMODEL::BE_UNDELETED)->where('id')->eq($actionID)->exec(); $this->create($action->objectType, $action->objectID, 'undeleted'); }
/** * 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(); }