Redmine/inc/project.class.php
Gemini 80d1576a80 Redmine Integration 1.3.0
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>
2026-06-29 18:32:19 -03:00

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()
]);
}
}