getType() == 'Project') { return self::createTabEntry(__('Redmine', 'redmine'), 0, $item::getType(), 'fas fa-sitemap'); } return ''; } static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { if ($item->getType() == 'Project') { self::showForProject($item); } return true; } static function getIcon() { return 'fas fa-sitemap'; } static function showForProject(Project $project) { global $DB, $CFG_GLPI; $projects_id = $project->getID(); $form_url = $CFG_GLPI['root_doc'] . '/plugins/redmine/front/project.form.php'; // Build {id: name} of Redmine projects from cache IN PHP (Twig's merge // renumbers integer keys, which corrupts the option values). $project_options = self::getRedmineProjectOptions(); // Already linked? $iterator = $DB->request([ 'FROM' => 'glpi_plugin_redmine_projects', 'WHERE' => ['projects_id' => $projects_id] ]); if (count($iterator) > 0) { $link = $iterator->current(); $redmineProjectId = (int) $link['redmine_project_id']; $cat_options = []; foreach (PluginRedmineRedmineapi::getProjectCategories($redmineProjectId) as $c) { if (isset($c['id'], $c['name'])) { $cat_options[$c['id']] = $c['name']; } } \Glpi\Application\View\TemplateRenderer::getInstance()->display('@redmine/project_linked.html.twig', [ 'action_url' => $form_url, 'owner_field' => 'projects_id', 'owner_id' => $projects_id, 'redmine_project_id' => $redmineProjectId, 'redmine_project_name' => $project_options[$redmineProjectId] ?? '', 'cat_options' => $cat_options, 'default_category_id' => (int) ($link['default_category_id'] ?? 0), 'csrf_token_value' => Session::getNewCSRFToken(), ]); return; } $description = \Glpi\RichText\RichText::getTextFromHtml($project->fields['content'], false, true, true); \Glpi\Application\View\TemplateRenderer::getInstance()->display('@redmine/project_form.html.twig', [ 'action_url' => $form_url, 'owner_field' => 'projects_id', 'owner_id' => $projects_id, 'project_options' => self::getRedmineProjectOptions(true), 'custom_fields' => self::getProjectCustomFieldDefs(), 'tracker_options' => self::getTrackerOptions(), 'default_tracker_ids' => ($dt = (int) (PluginRedmineConfig::getConfigRow()['default_tracker_id'] ?? 0)) ? [$dt] : [], 'project_name' => $project->fields['name'], 'project_description' => $description, 'project_identifier' => 'glpi-proj-' . $projects_id, 'modules' => self::getModules(), 'csrf_token_value' => Session::getNewCSRFToken() ]); } /** * {id: name} map of the cached Redmine projects (PHP preserves integer keys). * @return array */ static function getRedmineProjectOptions($activeOnly = false) { global $DB; $it = $DB->request(['FROM' => 'glpi_plugin_redmine_configs', 'WHERE' => ['id' => 1]]); $config = count($it) > 0 ? $it->current() : []; $metadata = !empty($config['metadata_cache']) ? json_decode($config['metadata_cache'], true) : []; $opts = []; foreach (($metadata['projects'] ?? []) as $rp) { if (!isset($rp['id'], $rp['name'])) { continue; } // status: 1=ativo, 5=fechado, 9=arquivado. Issues só podem ser // criadas em projetos ativos, então o dropdown só mostra esses. if ($activeOnly && isset($rp['status']) && (int) $rp['status'] !== 1) { continue; } $opts[$rp['id']] = $rp['name']; } return $opts; } /** * {id: name} map of the cached Redmine trackers (for the create form). * @return array */ static function getTrackerOptions() { global $DB; $it = $DB->request(['FROM' => 'glpi_plugin_redmine_configs', 'WHERE' => ['id' => 1]]); $config = count($it) > 0 ? $it->current() : []; $metadata = !empty($config['metadata_cache']) ? json_decode($config['metadata_cache'], true) : []; $opts = []; foreach (($metadata['trackers'] ?? []) as $t) { if (isset($t['id'], $t['name'])) { $opts[$t['id']] = $t['name']; } } return $opts; } /** * Project custom field definitions for the create form (from metadata cache). * Some Redmine setups make these mandatory on project creation. * @return array of ['id','name','field_format','is_required','options'=>{value: value}] */ static function getProjectCustomFieldDefs() { global $DB; $it = $DB->request(['FROM' => 'glpi_plugin_redmine_configs', 'WHERE' => ['id' => 1]]); $config = count($it) > 0 ? $it->current() : []; $metadata = !empty($config['metadata_cache']) ? json_decode($config['metadata_cache'], true) : []; $defs = []; foreach (($metadata['project_custom_fields'] ?? []) as $f) { $options = []; foreach (($f['possible_values'] ?? []) as $pv) { if (isset($pv['value'])) { $options[$pv['value']] = $pv['value']; } } $defs[] = [ 'id' => (int) $f['id'], 'name' => $f['name'], 'field_format' => $f['field_format'] ?? 'string', 'is_required' => (bool) ($f['is_required'] ?? false), 'options' => $options, ]; } return $defs; } /** * Redmine project modules offered on creation. * @return array */ static function getModules() { return [ 'issue_tracking' => 'Gerenciamento de Tarefas', 'time_tracking' => 'Gerenciamento de tempo', 'news' => 'Notícias', 'documents' => 'Documentos', 'files' => 'Arquivos', 'wiki' => 'Wiki', 'repository' => 'Repositório', 'boards' => 'Fóruns', 'calendar' => 'Calendário', 'gantt' => 'Gantt' ]; } }