saveLogs('Run Method ' . __FUNCTION__); $desc = $this->dao->query('DESC ' . TABLE_FEEDBACKVIEW)->fetchAll(); $this->saveLogs($this->dao->get()); $hasProductsField = false; foreach($desc as $field) { if($field->Field == 'products') $hasProductsField = true; } if(!$hasProductsField) return true; $feedbackView = $this->dao->select('account, products')->from(TABLE_FEEDBACKVIEW)->fetchPairs(); $this->dao->delete()->from(TABLE_FEEDBACKVIEW)->exec(); $this->saveLogs($this->dao->get()); foreach($feedbackView as $account => $products) { if(empty($products)) continue; foreach(explode(',', $products) as $productID) { $productID = trim($productID); if(empty($productID)) continue; $view = new stdclass(); $view->account = $account; $view->product = $productID; $this->dao->replace(TABLE_FEEDBACKVIEW)->data($view)->exec(); $this->saveLogs($this->dao->get()); } } $this->dao->exec("ALTER TABLE " . TABLE_FEEDBACKVIEW . " DROP `products`"); $this->saveLogs($this->dao->get()); return true; } /** * Import zentao module for workflow. * * @access public * @return void */ public function importBuildinModules() { $this->saveLogs('Run Method ' . __FUNCTION__); $this->loadModel('workflow'); $this->loadModel('workflowaction'); $this->loadModel('workflowfield'); $this->loadModel('workflowlayout'); $modules = $this->config->workflow->buildin->modules; $actions = $this->config->workflowaction->buildin->actions; $actionTypes = $this->config->workflowaction->buildin->types; $actionMethods = $this->config->workflowaction->buildin->methods; $actionOpens = $this->config->workflowaction->buildin->opens; $actionLayouts = $this->config->workflowaction->buildin->layouts; $actionPositions = $this->config->workflowaction->buildin->positions; $actionShows = $this->config->workflowaction->buildin->shows; $fields = $this->config->workflowfield->buildin->fields; $layouts = $this->config->workflowlayout->buildin->layouts; $account = $this->app->user->account; $now = helper::now(); /* Insert buildin modules to TABLE_WORKFLOW. */ $data = new stdclass(); $data->buildin = 1; $data->createdBy = $account; $data->createdDate = $now; $data->status = 'normal'; foreach($modules as $app => $appModules) { $data->app = $app; foreach($appModules as $module => $options) { $this->app->loadLang($module); $data->module = $module; $data->name = isset($this->lang->$module->common) ? $this->lang->$module->common : $module; $data->table = str_replace('`', '', zget($options, 'table', '')); $data->navigator = zget($options, 'navigator', 'secondary'); if($module == 'story') $data->name = $this->lang->searchObjects['story']; if($module == 'execution') $data->name = $this->lang->workflow->execution; $this->dao->replace(TABLE_WORKFLOW)->data($data)->exec(); } } /* Insert actions of buildin modules to TABLE_WORKFLOWACTION. */ $data = new stdclass(); $data->buildin = 1; $data->role = 'buildin'; $data->extensionType = 'none'; $data->createdBy = $account; $data->createdDate = $now; foreach($actions as $module => $moduleActions) { $data->module = $module; foreach($moduleActions as $action) { $data->action = $action; /* Use default action name if not set flow action name. */ $name = ''; if(isset($this->lang->$module->$action)) $name = $this->lang->$module->$action; if(empty($name) && in_array($action, array_keys($this->config->flowAction))) { $methodName = $this->config->flowAction[$action]; if(isset($this->lang->$module->$methodName)) $name = $this->lang->$module->$methodName; } if(empty($name) && isset($this->lang->workflowaction->default->actions[$action])) $name = $this->lang->workflowaction->default->actions[$action]; if(empty($name)) $name = $action; $data->name = $name; $data->method = $data->action; $data->open = 'normal'; $data->layout = 'normal'; $data->type = 'single'; $data->position = 'browseandview'; $data->show = 'direct'; if(isset($actionMethods[$module][$action])) $data->method = $actionMethods[$module][$action]; if(isset($actionOpens[$module][$action])) $data->open = $actionOpens[$module][$action]; if(isset($actionLayouts[$module][$action])) $data->layout = $actionLayouts[$module][$action]; if(isset($actionTypes[$module][$action])) $data->type = $actionTypes[$module][$action]; if(isset($actionPositions[$module][$action])) $data->position = $actionPositions[$module][$action]; if(isset($actionShows[$module][$action])) $data->show = $actionShows[$module][$action]; $this->dao->replace(TABLE_WORKFLOWACTION)->data($data)->exec(); } } /* Insert fields of buildin modules to TABLE_WORKFLOWFIELD. */ $data = new stdclass(); $data->role = 'buildin'; $data->createdBy = $account; $data->createdDate = $now; foreach($fields as $module => $moduleFields) { $order = 1; $data->module = $module; foreach($moduleFields as $field => $options) { $data->field = $field; $data->name = isset($this->lang->$module->$field) ? $this->lang->$module->$field : $field; $data->type = zget($options, 'type', 'varchar'); $data->length = zget($options, 'length', ''); $data->control = zget($options, 'control', 'input'); $data->options = zget($options, 'options', '[]'); $data->default = zget($options, 'default', ''); $data->buildin = zget($options, 'buildin', 1); $data->order = $order++; $data->readonly = ($field == 'subStatus') ? '0' : '1'; $data->rules = zget($options, 'rules', ''); if($module == 'execution') { $execField = 'exec' . ucfirst($field); if(isset($this->lang->$module->$execField)) $data->name = $this->lang->$module->$execField; } if(is_object($data->options) or is_array($data->options)) $data->options = helper::jsonEncode($data->options); $this->dao->replace(TABLE_WORKFLOWFIELD)->data($data)->exec(); } } /* Insert layouts of buildin modules to TABLE_WORKFLOWLAYOUT. */ $data = new stdclass(); foreach($layouts as $module => $moduleLayouts) { $data->module = $module; foreach($moduleLayouts as $action => $layoutFields) { $order = 1; $data->action = $action; foreach($layoutFields as $field => $options) { $data->field = $field; $data->width = zget($options, 'width', 0); $data->mobileShow = zget($options, 'mobileShow', 0); $data->order = $order++; $this->dao->replace(TABLE_WORKFLOWLAYOUT)->data($data)->exec(); } } } /* Insert labels of buildin modules to TABLE_WORKFLOWLABEL. */ $data = new stdclass(); $data->buildin = 1; $data->role = 'buildin'; $data->params = '[]'; $data->createdBy = $account; $data->createdDate = $now; foreach($modules as $app => $appModules) { foreach($appModules as $module => $options) { $labels = array(); if($module == 'product') { if(isset($this->lang->product->featureBar['all'])) $labels = $this->lang->product->featureBar['all']; } elseif($module == 'story') { if(isset($this->lang->product->featureBar['browse'])) $labels = $this->lang->product->featureBar['browse']; } elseif($module == 'execution') { if(isset($this->lang->execution->featureBar['all'])) $labels = $this->lang->execution->featureBar['all']; } elseif($module == 'task') { if(isset($this->lang->execution->featureBar['task'])) $labels = $this->lang->execution->featureBar['task']; } elseif($module == 'bug') { if(isset($this->lang->bug->featureBar['browse'])) $labels = $this->lang->bug->featureBar['browse']; } elseif($module == 'feedback') { if(isset($this->lang->feedback->menu) && (is_object($this->lang->feedback->menu) or is_array($this->lang->feedback->menu))) { foreach($this->lang->feedback->menu as $key => $menuItem) { $menus = explode('|', zget($menuItem, 'link', $menuItem)); $labels[$key] = zget($menus, 0, $menuItem); } } } else { if(isset($this->lang->$module->featureBar['browse'])) $labels = $this->lang->$module->featureBar['browse']; } $order = 1; $data->module = $module; foreach($labels as $key => $label) { $data->code = $key; $data->label = trim(strip_tags($label)); $data->order = $order++; $this->dao->replace(TABLE_WORKFLOWLABEL)->data($data)->exec(); } } } $this->importLiteModules(); } /** * Import lite modules. * * @access public * @return void */ public function importLiteModules() { $this->loadModel('workflow'); $this->loadModel('workflowaction'); $this->loadModel('workflowlayout'); $liteModules = $this->config->workflow->buildin->liteModules; foreach($liteModules as $moduleName) { $workflow = $this->dao->select('*')->from(TABLE_WORKFLOW) ->where('module')->eq($moduleName) ->fetch(); if(empty($workflow)) continue; unset($workflow->id); $workflow->vision = 'lite'; if($workflow->module == 'task') $workflow->app == 'project'; $this->dao->replace(TABLE_WORKFLOW)->data($workflow)->exec(); $workflowActions = $this->dao->select('*')->from(TABLE_WORKFLOWACTION) ->where('module')->eq($moduleName) ->fetchAll(); foreach($workflowActions as $workflowAction) { unset($workflowAction->id); $workflowAction->vision = 'lite'; $this->dao->replace(TABLE_WORKFLOWACTION)->data($workflowAction)->exec(); } $workflowLayouts = $this->dao->select('*')->from(TABLE_WORKFLOWLAYOUT) ->where('module')->eq($moduleName) ->fetchAll(); foreach($workflowLayouts as $workflowLayout) { unset($workflowLayout->id); $workflowLayout->vision = 'lite'; $this->dao->replace(TABLE_WORKFLOWLAYOUT)->data($workflowLayout)->exec(); } } } /** * Add sub status for built-in modules. * * @access public * @return bool */ public function addSubStatus() { $this->saveLogs('Run Method ' . __FUNCTION__); $this->app->loadModuleConfig('workflow'); $modules = $this->config->workflow->buildin->subStatus->modules; $statusOrders = $this->dao->select('module, `order`')->from(TABLE_WORKFLOWFIELD) ->where('field')->eq('status') ->andWhere('module')->in($modules) ->fetchPairs(); $field = new stdclass(); $field->field = 'subStatus'; $field->type = 'varchar'; $field->length = 30; $field->control = 'select'; $field->buildin = 0; $field->role = 'buildin'; $field->options = '[]'; foreach($modules as $module) { $this->app->loadLang($module); $order = $statusOrders[$module] + 1; $field->module = $module; $field->name = $this->lang->$module->subStatus; $field->order = $order; $this->dao->replace(TABLE_WORKFLOWFIELD)->data($field)->exec(); $this->dao->update(TABLE_WORKFLOWFIELD)->set('`order` = `order` + 1') ->where('module')->eq($module) ->andWhere('`order`')->gt($order) ->exec(); } return !dao::isError(); } /** * Add batch create action and batch edit action for exist flows. * * @access public * @return bool */ public function addDefaultActions() { $this->saveLogs('Run Method ' . __FUNCTION__); $this->loadModel('workflowaction'); $actionLang = $this->lang->workflowaction->default; $actionConfig = $this->config->workflowaction->default; $defaultActions = $this->config->workflowaction->defaultActions; $flows = $this->dao->select('module,buildin')->from(TABLE_WORKFLOW)->where('type')->eq('flow')->fetchPairs('module', 'buildin'); $action = new stdclass(); $action->show = 'direct'; $action->createdBy = $this->app->user->account; $action->createdDate = helper::now(); foreach($flows as $module => $buildin) { if($buildin) continue; $action->module = $module; foreach($defaultActions as $actionCode) { $action->action = $actionCode; $action->name = $actionLang->actions[$actionCode]; $action->type = $actionConfig->types[$actionCode]; $action->batchMode = $actionConfig->batchModes[$actionCode]; $action->open = $actionConfig->opens[$actionCode]; $action->position = $actionConfig->positions[$actionCode]; $this->dao->replace(TABLE_WORKFLOWACTION)->data($action)->autoCheck()->exec(); } } return !dao::isError(); } /** * process sub tables. * * @access public * @return void */ public function processSubTables() { $this->saveLogs('Run Method ' . __FUNCTION__); $subTables = $this->dao->select('parent, module')->from(TABLE_WORKFLOW) ->where('parent')->ne('') ->andWhere('type')->eq('table') ->fetchPairs(); foreach($subTables as $parent => $module) { $this->dao->update(TABLE_WORKFLOWLAYOUT) ->set('field')->eq('sub_' . $module) ->where('module')->eq($parent) ->andWhere('field')->eq($module) ->exec(); } return !dao::isError(); } /** * Import caselib module for workflow. * * @access public * @return void */ public function importCaseLibModule() { $this->saveLogs('Run Method ' . __FUNCTION__); $this->loadModel('workflow'); $this->loadModel('workflowaction'); $this->loadModel('workflowfield'); $this->loadModel('workflowlayout'); $caselibOptions = $this->config->workflow->buildin->modules->qa->caselib; $actions = $this->config->workflowaction->buildin->actions['caselib']; $actionOpens = $this->config->workflowaction->buildin->opens['caselib']; $fields = $this->config->workflowfield->buildin->fields['caselib']; $layouts = $this->config->workflowlayout->buildin->layouts->caselib; $account = $this->app->user->account; $now = helper::now(); /* Insert buildin modules to TABLE_WORKFLOW. */ $this->app->loadLang('caselib'); $data = new stdclass(); $data->buildin = 1; $data->createdBy = $account; $data->createdDate = $now; $data->app = 'qa'; $data->module = 'caselib'; $data->name = isset($this->lang->caselib->common) ? $this->lang->caselib->common : 'caselib'; $data->table = str_replace('`', '', zget($caselibOptions, 'table', '')); $data->navigator = zget($caselibOptions, 'navigator', 'secondary'); $this->dao->replace(TABLE_WORKFLOW)->data($data)->exec(); /* Insert actions of buildin modules to TABLE_WORKFLOWACTION. */ $data = new stdclass(); $data->buildin = 1; $data->extensionType = 'none'; $data->createdBy = $account; $data->createdDate = $now; $data->module = 'caselib'; foreach($actions as $action) { $data->action = $action; $data->name = isset($this->lang->caselib->$action) ? $this->lang->caselib->$action : $action; $data->open = isset($actionOpens['caselib'][$action]) ? $actionOpens['caselib'][$action] : 'normal'; $data->layout = 'normal'; $this->dao->replace(TABLE_WORKFLOWACTION)->data($data)->exec(); } /* Insert fields of buildin modules to TABLE_WORKFLOWFIELD. */ $data = new stdclass(); $data->createdBy = $account; $data->createdDate = $now; $data->module = 'caselib'; $order = 1; foreach($fields as $field => $options) { $data->field = $field; $data->name = isset($this->lang->caselib->$field) ? $this->lang->caselib->$field : $field; $data->type = zget($options, 'type', 'varchar'); $data->length = zget($options, 'length', ''); $data->control = zget($options, 'control', 'input'); $data->options = zget($options, 'options', '[]'); $data->default = zget($options, 'default', ''); $data->buildin = zget($options, 'buildin', 1); $data->order = $order++; $data->readonly = ($field == 'subStatus') ? '0' : '1'; if(is_object($data->options) or is_array($data->options)) $data->options = helper::jsonEncode($data->options); $this->dao->replace(TABLE_WORKFLOWFIELD)->data($data)->exec(); } /* Insert layouts of buildin modules to TABLE_WORKFLOWLAYOUT. */ $data = new stdclass(); $data->module = 'caselib'; foreach($layouts as $action => $layoutFields) { $order = 1; $data->action = $action; foreach($layoutFields as $field => $options) { $data->field = $field; $data->width = zget($options, 'width', 0); $data->mobileShow = zget($options, 'mobileShow', 0); $data->order = $order++; $this->dao->replace(TABLE_WORKFLOWLAYOUT)->data($data)->exec(); } } } /** * Delete buildin fields. * * @access public * @return void */ public function deleteBuildinFields() { $this->saveLogs('Run Method ' . __FUNCTION__); $deleteIdList = $this->dao->select('t1.id')->from(TABLE_WORKFLOWLAYOUT)->alias('t1') ->leftJoin(TABLE_WORKFLOWFIELD)->alias('t2')->on('t1.field=t2.field && t1.module = t2.module') ->leftJoin(TABLE_WORKFLOWACTION)->alias('t3')->on('t1.action=t3.action && t1.module = t3.module') ->where('t2.buildin')->eq(1) ->andWhere('t3.extensionType')->eq('extend') ->fetchPairs('id', 'id'); $this->dao->delete()->from(TABLE_WORKFLOWLAYOUT)->where('id')->in($deleteIdList)->exec(); } /** * Add new actions for exist flows. * * @access public * @return bool */ public function addWorkflowActions() { $this->saveLogs('Run Method ' . __FUNCTION__); $this->loadModel('workflowaction'); $newActions = array('batchcreate', 'batchedit', 'link', 'unlink', 'exporttemplate', 'import', 'showimport'); $actionLang = $this->lang->workflowaction->default; $actionConfig = $this->config->workflowaction->default; $flows = $this->dao->select('module,buildin')->from(TABLE_WORKFLOW)->where('type')->eq('flow')->fetchPairs('module', 'buildin'); $action = new stdclass(); $action->show = 'direct'; $action->createdBy = $this->app->user->account; $action->createdDate = helper::now(); foreach($flows as $module => $buildin) { $action->module = $module; foreach($newActions as $actionCode) { if($buildin and !in_array($actionCode, zget($this->config->workflowaction->buildin->actions, $module, array()))) continue; $open = $actionConfig->opens[$actionCode]; if($buildin and isset($this->config->workflowaction->buildin->opens[$module][$actionCode])) $open = $this->config->workflowaction->buildin->opens[$module][$actionCode]; $action->action = $actionCode; $action->name = $actionLang->actions[$actionCode]; $action->type = $actionConfig->types[$actionCode]; $action->batchMode = $actionConfig->batchModes[$actionCode]; $action->open = $open; $action->position = $actionConfig->positions[$actionCode]; $action->buildin = $buildin; $action->layout = 'normal'; $action->extensionType = $buildin ? 'none' : 'override'; $this->dao->replace(TABLE_WORKFLOWACTION)->data($action)->autoCheck()->exec(); } } $this->dao->update(TABLE_WORKFLOWACTION)->set('name')->eq($actionLang->actions['export'])->where('action')->eq('export')->exec(); return !dao::isError(); } /** * Process workflow layout. * * @access public * @return bool */ public function processWorkflowLayout() { $this->saveLogs('Run Method ' . __FUNCTION__); $subTables = $this->dao->select('parent, module')->from(TABLE_WORKFLOW) ->where('parent')->ne('') ->andWhere('type')->eq('table') ->fetchPairs(); foreach($subTables as $parent => $module) { $this->dao->update(TABLE_WORKFLOWLAYOUT) ->set('field')->eq('sub_' . $module) ->where('module')->eq($parent) ->andWhere('field')->eq($module) ->exec(); } return !dao::isError(); } /** * Make sure the params of a label has the condition deleted='0'. * * @access public * @return bool */ public function processWorkflowLabel() { $this->saveLogs('Run Method ' . __FUNCTION__); $labels = $this->dao->select('id, params')->from(TABLE_WORKFLOWLABEL)->where('module')->eq('test')->fetchPairs(); foreach($labels as $id => $params) { $index = 0; $deleted = false; $params = json_decode($params, true); foreach($params as $index => $param) { if(zget($param, 'field') == 'deleted' && zget($param, 'operator') == '=' && zget($param, 'value') == '0') { $deleted = true; break; } } if(!$deleted) { $index++; $params[$index]['field'] = 'deleted'; $params[$index]['operator'] = '='; $params[$index]['value'] = '0'; $params = array_reverse($params); } $params = helper::jsonEncode($params); $this->dao->update(TABLE_WORKFLOWLABEL)->set('params')->eq($params)->where('id')->eq($id)->exec(); } return !dao::isError(); } /** * Process workflow conditions to array. * * @access public * @return bool */ public function processWorkflowCondition() { $this->saveLogs('Run Method ' . __FUNCTION__); $actions = $this->dao->select('id, conditions')->from(TABLE_WORKFLOWACTION)->fetchPairs(); foreach($actions as $id => $conditions) { $conditions = json_decode($conditions); if(!$conditions) continue; $conditions = helper::jsonEncode(array($conditions)); $this->dao->update(TABLE_WORKFLOWACTION)->set('conditions')->eq($conditions)->where('id')->eq($id)->exec(); } return !dao::isError(); } /** * Process workflow fields. * * @access public * @return void */ public function processWorkflowFields() { $sqls['id'] = "ALTER TABLE %s CHANGE `id` `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT"; $sqls['parent'] = "ALTER TABLE %s CHANGE `parent` `parent` mediumint(8) unsigned NOT NULL"; $sqls['assignedTo'] = "ALTER TABLE %s CHANGE `assignedTo` `assignedTo` varchar(30) NOT NULL"; $sqls['status'] = "ALTER TABLE %s CHANGE `status` `status` varchar(30) NOT NULL"; $sqls['subStatus'] = "ALTER TABLE %s CHANGE `subStatus` `subStatus` varchar(30) NOT NULL"; $sqls['createdBy'] = "ALTER TABLE %s CHANGE `createdBy` `createdBy` varchar(30) NOT NULL"; $sqls['createdDate'] = "ALTER TABLE %s CHANGE `createdDate` `createdDate` datetime NOT NULL"; $sqls['editedBy'] = "ALTER TABLE %s CHANGE `editedBy` `editedBy` varchar(30) NOT NULL"; $sqls['editedDate'] = "ALTER TABLE %s CHANGE `editedDate` `editedDate` datetime NOT NULL"; $sqls['assignedBy'] = "ALTER TABLE %s CHANGE `assignedBy` `assignedBy` varchar(30) NOT NULL"; $sqls['assignedDate'] = "ALTER TABLE %s CHANGE `assignedDate` `assignedDate` datetime NOT NULL"; $sqls['deleted'] = "ALTER TABLE %s CHANGE `deleted` `deleted` enum('0', '1') NOT NULL DEFAULT '0'"; $flows = $this->dao->select('module, `table`')->from(TABLE_WORKFLOW) ->where('type')->eq('flow') ->andWhere('buildin')->eq('0') ->orderBy('id_desc') ->fetchPairs(); $fields = $this->dao->select('module, field, `default`')->from(TABLE_WORKFLOWFIELD) ->where('module')->in(array_keys($flows)) ->fetchGroup('module', 'field'); $magicQuote = (version_compare(phpversion(), '5.4', '<') and function_exists('get_magic_quotes_gpc') and get_magic_quotes_gpc()); foreach($flows as $module => $table) { foreach($sqls as $field => $sql) { if(!isset($fields[$module][$field])) continue; $sql = sprintf($sql, $table); if($field == 'status' or $field == 'subStatus') { $default = $fields[$module][$field]->default; if($default) { if($magicQuote) $default = stripslashes($default); $default = $this->dbh->quote($default); $sql .= " DEFAULT {$default}"; } } try { $this->dbh->query($sql); } catch(PDOException $e) { self::$errors[] = $e->getMessage() . "

The sql is: $sql

"; return false; } } } return true; } public function processFlowStatus() { $this->loadModel('workflow', 'flow'); $this->app->loadLang('workflowfield', 'flow'); $this->app->loadModuleConfig('workflowfield', 'flow'); $flowPairs = $this->dao->select('module')->from(TABLE_WORKFLOW)->where('type')->eq('flow')->andWhere('buildin')->eq(0)->fetchPairs(); foreach($flowPairs as $module) { $errors = array(); $actions = $this->dao->select('action, name')->from(TABLE_WORKFLOWACTION)->where('module')->eq($module)->andWhere('open')->ne('none')->fetchPairs(); $fields = $this->dao->select('id')->from(TABLE_WORKFLOWFIELD)->where('module')->eq($module)->andWhere('field')->notin(array_keys($this->config->workflowfield->default->fields))->fetchPairs(); $layoutFields = $this->dao->select('DISTINCT action')->from(TABLE_WORKFLOWLAYOUT)->where('module')->eq($module)->andWhere('action')->in(array_keys($actions))->andWhere('field')->notin('actions,file')->fetchPairs(); foreach($actions as $action => $name) { if(isset($layoutFields[$action])) { unset($actions[$action]); continue; } } if(empty($fields)) $errors[] = 'emptyCustomField'; if(!empty($actions)) $errors[] = 'emptyLayout'; $status = !empty($errors) ? 'wait' : 'normal'; $this->dao->update(TABLE_WORKFLOW)->set('status')->eq($status)->where('module')->eq($module)->exec(); } return !dao::isError(); } public function addMailtoFields() { $this->app->loadLang('workflowfield'); $mailto = new stdclass(); $mailto->field = 'mailto'; $mailto->control = 'multi-select'; $mailto->type = 'text'; $mailto->name = $this->lang->workflowfield->default->fields['mailto']; $mailto->options = 'user'; $mailto->readonly = 1; $flows = $this->dao->select('module, `table`')->from(TABLE_WORKFLOW)->where('`type`')->eq('flow')->fetchPairs(); foreach($flows as $module => $table) { $hasMailto = false; $fields = $this->dbh->query("DESC $table")->fetchAll(); foreach($fields as $field) { if($field->Field == 'mailto') { $hasMailto = true; break; } } if(!$hasMailto) { $mailto->module = $module; $this->dao->insert(TABLE_WORKFLOWFIELD)->data($mailto)->autoCheck()->exec(); if(dao::isError()) return false; try { $sql = "ALTER TABLE `{$table}` ADD `mailto` text NOT NULL"; $this->dbh->query($sql); } catch(PDOException $exception) { self::$errors[] = $exception->getMessage() . "

The sql is: $sql

"; return false; } } } return true; } /** * Update attend status. * * @access public * @return bool */ public function updateAttendStatus() { /* Get leave list. */ $leaveList = $this->loadModel('leave')->getList('personal', '', '', '', '', 'pass'); /* Cycle leave list to modify the attend status. */ foreach($leaveList as $leave) { $this->dao->update(TABLE_ATTEND) ->set('status')->eq('leave') ->set('reason')->eq('leave') ->where('`date`')->between($leave->begin, $leave->end) ->andWhere('account')->eq($leave->createdBy) ->exec(); } return true; } /** * Init view for workflow datasource. * * @access public * @return bool */ public function initView4WorkflowDatasource() { $datasources = $this->dao->select('*')->from(TABLE_WORKFLOWDATASOURCE)->where('type')->eq('sql')->andWhere('view')->eq('')->fetchAll('id'); foreach($datasources as $id => $datasource) { $options = array(); try { $view = 'view_datasource_tmp'; $sql = "CREATE VIEW $view AS {$datasource->datasource}"; $this->dbh->query($sql); $fields = $this->dbh->query("DESC $view")->fetchAll(); foreach($fields as $field) $options[$field->Field] = $field->Field; $sql = "DROP VIEW $view"; $this->dbh->query($sql); } catch(PDOException $exception) { } try { $view = "view_datasource_$id"; $keyField = array_shift($options); $valueField = array_shift($options); $sqls = array(); $sqls[] = "DROP VIEW IF EXISTS $view"; $sqls[] = "CREATE VIEW $view AS $datasource->datasource"; foreach($sqls as $sql) $this->dbh->query($sql); $this->dao->update(TABLE_WORKFLOWDATASOURCE)->set('view')->eq($view)->set('keyField')->eq($keyField)->set('valueField')->eq($valueField)->where('id')->eq($id)->exec(); } catch(PDOException $exception) { dao::getError(); } } return true; } /** * Adjust priv for biz5_0_1. * * @access public * @return bool */ public function adjustPrivBiz5_0_1() { $feedbackGroups = $this->dao->select('id')->from(TABLE_GROUP)->where('developer')->eq('0')->fetchPairs('id', 'id'); foreach($feedbackGroups as $group) { $grouppriv = new stdclass(); $grouppriv->group = $group; $grouppriv->module = 'my'; $grouppriv->method = 'calendar'; $this->dao->replace(TABLE_GROUPPRIV)->data($grouppriv)->exec(); $grouppriv->module = 'todo'; $grouppriv->method = 'calendar'; $this->dao->replace(TABLE_GROUPPRIV)->data($grouppriv)->exec(); $grouppriv->module = 'my'; $grouppriv->method = 'todo'; $this->dao->replace(TABLE_GROUPPRIV)->data($grouppriv)->exec(); } return true; } public function updateWorkflow4Execution() { $workflowAction = $this->dao->select('*')->from(TABLE_WORKFLOWACTION)->where('module')->eq('execution')->andWhere('action')->eq('create')->fetch(); if(empty($workflowAction)) { $this->dao->update(TABLE_WORKFLOWACTION)->set('module')->eq('execution')->where('module')->eq('project')->exec(); $this->dao->delete()->from(TABLE_WORKFLOWACTION)->where('module')->eq('execution')->andWhere('action')->eq('browse')->exec(); $this->dao->exec("REPLACE INTO " . TABLE_WORKFLOWACTION . "(`module`, `action`, `name`, `type`, `batchMode`, `extensionType`, `open`, `position`, `layout`, `show`, `order`, `buildin`, `virtual`, `conditions`, `verifications`, `hooks`, `linkages`, `js`, `css`, `toList`, `blocks`, `desc`, `status`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES ('project', 'browse', '项目列表', 'single', 'different', 'none', 'normal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'create', '创建项目', 'single', 'different', 'none', 'normal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'batchedit', '批量编辑', 'single', 'different', 'none', 'normal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'edit', '编辑项目', 'single', 'different', 'none', 'normal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'view', '项目概况', 'single', 'different', 'none', 'normal', 'browseandview', 'side', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'delete', '删除项目', 'single', 'different', 'none', 'none', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'close', '关闭项目', 'single', 'different', 'none', 'modal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'activate', '激活项目', 'single', 'different', 'none', 'modal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'start', '启动项目', 'single', 'different', 'none', 'modal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'suspend', '挂起项目', 'single', 'different', 'none', 'modal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('execution', 'task', '任务列表', 'single', 'different', 'none', 'normal', 'browseandview', 'normal', 'dropdownlist', 0, 1, 0, '', '', '', '', '', '', '', '', '', 'enable', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00')"); } $workflowField = $this->dao->select('*')->from(TABLE_WORKFLOWFIELD)->where('module')->eq('execution')->limit(1)->fetch(); if(empty($workflowField)) { $this->dao->update(TABLE_WORKFLOWFIELD)->set('module')->eq('execution')->where('module')->eq('project')->exec(); $this->dao->update(TABLE_WORKFLOWFIELD)->set('field')->eq('project')->where('module')->eq('execution')->andWhere('field')->eq('parent')->exec(); $this->dao->exec("REPLACE INTO " . TABLE_WORKFLOWFIELD . " (`module`, `field`, `type`, `length`, `name`, `control`, `expression`, `options`, `default`, `rules`, `placeholder`, `order`, `searchOrder`, `exportOrder`, `canExport`, `canSearch`, `isValue`, `readonly`, `buildin`, `desc`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES ('project', 'id', 'mediumint', '8', '编号', 'input', '', '', '', '', '', 1, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', 'admin', '2021-07-28 16:58:48'), ('project', 'type', 'varchar', '20', '项目类型', 'select', '', '16', 'sprint', '', '', 2, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'model', 'char', '30', '项目管理方式', 'input', '', '', '', '', '', 3, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', 'admin', '2021-07-28 16:58:30'), ('project', 'parent', 'mediumint', '8', '所属项目集', 'input', '', '', '0', '', '', 4, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'name', 'varchar', '90', '项目名称', 'input', '', '', '', '', '', 5, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'budget', 'varchar', '30', '预算', 'input', '', '', '0', '', '', 7, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'budgetUnit', 'char', '30', '预算单位', 'input', '', '', 'CNY', '', '', 8, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', 'admin', '2021-07-28 16:58:42'), ('project', 'begin', 'date', '', '计划开始', 'input', '', '', '', '', '', 9, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'end', 'date', '', '计划完成', 'input', '', '', '', '', '', 10, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'days', 'smallint', '5', '可用工作日', 'input', '', '', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'status', 'varchar', '10', '状态', 'select', '', '17', '', '', '', 12, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'stage', 'enum', '', '阶段', 'input', '', '', '1', '', '', 13, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'pri', 'enum', '', '优先级', 'input', '', '', '1', '', '', 15, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'desc', 'text', '', '项目描述', 'input', '', '', '', '', '', 16, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'openedBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 17, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'openedDate', 'datetime', '', '创建日期', 'input', '', '', '', '', '', 18, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'closedBy', 'varchar', '30', '由谁关闭', 'select', '', 'user', '', '', '', 19, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'closedDate', 'datetime', '', '关闭日期', 'input', '', '', '', '', '', 20, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'canceledBy', 'varchar', '30', '由谁取消', 'select', '', 'user', '', '', '', 21, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'canceledDate', 'datetime', '', '取消日期', 'input', '', '', '', '', '', 22, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'PO', 'varchar', '30', 'PO', 'select', '', 'user', '', '', '', 23, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'PM', 'varchar', '30', '负责人', 'select', '', 'user', '', '', '', 24, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'QD', 'varchar', '30', 'QD', 'select', '', 'user', '', '', '', 25, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'RD', 'varchar', '30', 'RD', 'select', '', 'user', '', '', '', 26, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'team', 'varchar', '90', '团队名称', 'input', '', '', '', '', '', 27, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'acl', 'enum', '', '访问控制', 'select', '', '18', 'open', '', '', 28, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'whitelist', 'text', '', '项目白名单', 'select', '', '7', '', '', '', 29, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'order', 'mediumint', '8', '排序', 'input', '', '', '', '', '', 30, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00'), ('project', 'deleted', 'enum', '', '已删除', 'select', '', '[\"\\u672a\\u5220\\u9664\",\"\\u5df2\\u5220\\u9664\"]', '0', '', '', 31, 0, 0, '0', '0', '0', '1', 1, '', '', '2021-07-28 16:54:38', '', '0000-00-00 00:00:00')"); } } /** * Add file fields. * * @access public * @return bool */ public function addFileFields() { $layoutModules = $this->dao->select('DISTINCT module')->from(TABLE_WORKFLOWLAYOUT)->where('field')->eq('file')->fetchPairs(); $relationModules = $this->dao->select('DISTINCT prev')->from(TABLE_WORKFLOWRELATIONLAYOUT)->where('field')->eq('file')->fetchPairs(); $modules = $layoutModules + $relationModules; if(!$modules) return true; $fileFields = $this->dao->select('*')->from(TABLE_WORKFLOWFIELD)->where('module')->in($modules)->andWhere('control')->eq('file')->andWhere('field')->eq('file')->fetchGroup('module', 'field'); $file = new stdclass(); $file->field = 'file'; $file->type = 'varchar'; $file->length = '255'; $file->name = $this->lang->files; $file->control = 'file'; $file->options = '[]'; foreach($modules as $module) { if(isset($fileFields[$module]['file'])) continue; $file->module = $module; $this->dao->replace(TABLE_WORKFLOWFIELD)->data($file)->exec(); } return true; } /** * Process feedback field. * * @access public * @return void */ public function processFeedbackField() { /* If feedback's closed reason is totask/tostory/tobug, change it to solution and set closed reason commented.*/ $feedbacks = $this->dao->select('id, closedReason')->from(TABLE_FEEDBACK)->where('deleted')->eq('0')->fetchAll(); foreach($feedbacks as $feedback) { $feedback->closedReason = strtolower($feedback->closedReason); if(in_array($feedback->closedReason, array('totask', 'tobug', 'totask', 'totodo'))) { $this->dao->update(TABLE_FEEDBACK) ->set('solution')->eq($feedback->closedReason) ->set('closedReason')->eq('commented') ->where('id')->eq($feedback->id) ->exec(); } } /* Process actions. */ $this->dao->update(TABLE_ACTION)->set('extra')->eq('commented') ->where('objectType')->eq('feedback') ->andWhere('action')->eq('closed') ->andWhere('(extra')->eq('ToStory') ->orWhere('extra')->eq('ToBug') ->orWhere('extra')->eq('ToTask') ->orWhere('extra')->eq('ToTodo') ->markRight(1) ->exec(); } /** * Add report actions. * * @access public * @return bool */ public function addReportActions() { $this->loadModel('workflowaction'); $actionCode = 'report'; $actionLang = $this->lang->workflowaction->default; $actionConfig = $this->config->workflowaction->default; $flows = $this->dao->select('module')->from(TABLE_WORKFLOW)->where('type')->eq('flow')->andWhere('buildin')->eq(0)->fetchPairs(); $actions = $this->dao->select('module')->from(TABLE_WORKFLOWACTION)->where('action')->eq($actionCode)->fetchPairs(); $action = new stdclass(); $action->action = $actionCode; $action->name = $actionLang->actions[$actionCode]; $action->type = zget($actionConfig->types, $actionCode, 'single'); $action->batchMode = zget($actionConfig->batchModes, $actionCode, 'different'); $action->open = $actionConfig->opens[$actionCode]; $action->position = $actionConfig->positions[$actionCode]; $action->show = 'direct'; $action->createdBy = $this->app->user->account; $action->createdDate = helper::now(); foreach($flows as $module) { if(isset($actions[$module])) continue; $action->module = $module; $this->dao->replace(TABLE_WORKFLOWACTION)->data($action)->autoCheck()->exec(); } return !dao::isError(); } /** * Process view fields. * * @access public * @return bool */ public function processViewFields() { $datasources = $this->dao->select('id, datasource, keyField, valueField')->from(TABLE_WORKFLOWDATASOURCE)->where('view')->ne('')->andWhere('buildin')->eq('0')->fetchAll(); foreach($datasources as $datasource) { try { $tmpView = 'view_datasource_tmp'; $sqls = array(); $sqls[] = "DROP VIEW IF EXISTS $tmpView"; $sqls[] = "CREATE VIEW $tmpView AS $datasource->datasource"; foreach($sqls as $sql) $this->dbh->query($sql); $sqlFields = $this->dbh->query("DESC $tmpView")->fetchAll(); $i = 1; $fields = array(); foreach($sqlFields as $field) { $fields[$field->Field] = "field{$i}";; $i++; } $sql = "DROP VIEW $tmpView"; $this->dbh->query($sql); $viewFields = implode(',', $fields); $view = "view_datasource_{$datasource->id}"; $sqls = array(); $sqls[] = "DROP VIEW IF EXISTS $view"; $sqls[] = "CREATE VIEW $view ($viewFields) AS $datasource->datasource"; foreach($sqls as $sql) $this->dbh->query($sql); $keyField = zget($fields, $datasource->keyField); $valueField = zget($fields, $datasource->valueField); $this->dao->update(TABLE_WORKFLOWDATASOURCE)->set('keyField')->eq($keyField)->set('valueField')->eq($valueField)->where('id')->eq($datasource->id)->exec(); } catch(PDOException $exception) { dao::$errors = $exception->getMessage(); return false; } } } /** * Process flow position. * * @access public * @return void */ public function processFlowPosition() { $customPrimaryFlows = $this->dao->select('module')->from(TABLE_WORKFLOW) ->where('buildin')->eq(0) ->andWhere('type')->eq('flow') ->andWhere('status')->eq('normal') ->andWhere('navigator')->eq('primary') ->fetchPairs('module', 'module'); $flows = $this->dao->select('id,app,position,module')->from(TABLE_WORKFLOW) ->where('buildin')->eq(0) ->andWhere('type')->eq('flow') ->andWhere('app')->in($customPrimaryFlows) ->andWhere('status')->eq('normal') ->andWhere('navigator')->eq('secondary') ->fetchAll(); foreach($flows as $flow) { $direction = strpos($flow->position, 'after') === 0 ? 'after' : 'before'; $position = substr($flow->position, strlen($direction)); if(preg_match('/^browse(\d+)/', $position)) { $position = $direction . $flow->app; $this->dao->update(TABLE_WORKFLOW)->set('position')->eq($position)->where('id')->eq($flow->id)->exec(); } } } }