Plugin de integração GLPI <-> Redmine: - Config nativa (Twig) com API key cifrada (GLPIKey) - Vínculo projeto GLPI <-> projeto Redmine (aba do projeto) + categoria por vínculo - 1 issue Redmine por chamado; defaults (tracker/priority/activity) e mapa de status - Tempo das TicketTasks -> time entries (gate em "Feito"), idempotente - Autores via impersonation (X-Redmine-Switch-User) + auto-membership por role - Mapeamento de usuários GLPI->Redmine (auto-match por e-mail + overrides) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
104 lines
3.7 KiB
PHP
104 lines
3.7 KiB
PHP
<?php
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
class PluginRedmineProject extends CommonDBTM {
|
|
|
|
static function getTypeName($nb = 0) {
|
|
return 'Redmine';
|
|
}
|
|
|
|
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
|
|
if ($item->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();
|
|
|
|
// Check if 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'];
|
|
|
|
// Issue categories are per Redmine project.
|
|
$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' => $CFG_GLPI['root_doc'] . '/plugins/redmine/front/project.form.php',
|
|
'projects_id' => $projects_id,
|
|
'redmine_project_id' => $redmineProjectId,
|
|
'cat_options' => $cat_options,
|
|
'default_category_id' => (int) ($link['default_category_id'] ?? 0),
|
|
'csrf_token_value' => Session::getNewCSRFToken(),
|
|
]);
|
|
return;
|
|
}
|
|
|
|
// Fetch Redmine Metadata Cache
|
|
$config_it = $DB->request(['FROM' => 'glpi_plugin_redmine_configs', 'WHERE' => ['id' => 1]]);
|
|
$config = count($config_it) > 0 ? $config_it->current() : [];
|
|
$metadata = [];
|
|
if (!empty($config['metadata_cache'])) {
|
|
$metadata = json_decode($config['metadata_cache'], true);
|
|
}
|
|
|
|
$redmine_projects = $metadata['projects'] ?? [];
|
|
|
|
$modules = [
|
|
'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'
|
|
];
|
|
|
|
// Strip HTML from description
|
|
$description = \Glpi\RichText\RichText::getTextFromHtml($project->fields['content'], false, true, true);
|
|
|
|
global $DB, $CFG_GLPI;
|
|
|
|
\Glpi\Application\View\TemplateRenderer::getInstance()->display('@redmine/project_form.html.twig', [
|
|
'action_url' => $CFG_GLPI['root_doc'] . '/plugins/redmine/front/project.form.php',
|
|
'projects_id' => $projects_id,
|
|
'redmine_projects' => $redmine_projects,
|
|
'project_name' => $project->fields['name'],
|
|
'project_description' => $description,
|
|
'project_identifier' => 'glpi-proj-' . $projects_id,
|
|
'modules' => $modules,
|
|
'csrf_token_value' => Session::getNewCSRFToken()
|
|
]);
|
|
}
|
|
}
|