Redmine/front/config.form.php
Gemini 1053b9f506 feat(2.0): Fase 2 — editor de templates na config + paleta + create_project
- seção "Templates de Payload (avançado)" no formconfig: card por operação,
  editor linha-a-linha (flatten/unflatten em JS puro) com toggle Ver JSON,
  Gerar template (seed + CFs descobertos), ativar/desativar
- paleta de variáveis clicável (copia tag) + referência do Redmine do ambiente
  (trackers/status/prioridades/atividades/custom fields com valores)
- buildFormContext (form.*) e wiring do create_project nos dois controllers,
  com fallback 1.x em erro de render
- validado: render da UI (4 cards + paleta + JS) e E2E create_project via
  template no Redmine dev (tipos nativos, identifier minúsculo, parent, trackers)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 16:04:22 -03:00

91 lines
3.6 KiB
PHP

<?php
include ("../../../inc/includes.php");
Session::checkRight("config", UPDATE);
$config = new PluginRedmineConfig();
global $DB;
if (isset($_POST["update"]) || isset($_POST["sync"])) {
// Save whatever was typed (URL/key/defaults) before anything else.
$config->update($_POST);
if (isset($_POST["sync"])) {
$metadata = PluginRedmineRedmineapi::syncMetadata();
if ($metadata !== false) {
$DB->update('glpi_plugin_redmine_configs', [
'metadata_cache' => json_encode($metadata)
], ['id' => 1]);
PluginRedmineRedmineapi::syncUsers(); // refresh Redmine user cache
Session::addMessageAfterRedirect(__('Metadados sincronizados com sucesso!', 'redmine'));
} else {
Session::addMessageAfterRedirect(__('Erro ao sincronizar com o Redmine. Verifique URL e chave.', 'redmine'), false, ERROR);
}
}
Html::back();
}
// Save a payload template (motor 2.0).
if (isset($_POST['save_template'])) {
$op = (string) ($_POST['template_op'] ?? '');
if (in_array($op, PluginRedmineTemplateengine::OPERATIONS, true)) {
$json = (string) ($_POST['template_json'] ?? '');
// Defensivo contra escaping de aspas na camada de entrada.
if ($json !== '' && json_decode($json, true) === null && json_decode(stripslashes($json), true) !== null) {
$json = stripslashes($json);
}
if ($json !== '' && json_decode($json, true) === null) {
Session::addMessageAfterRedirect(__('Template não é JSON válido — nada foi salvo.', 'redmine'), false, ERROR);
} else {
PluginRedmineTemplateengine::save($op, $json, !empty($_POST['template_active']) && $json !== '');
Session::addMessageAfterRedirect(__('Template salvo.', 'redmine'));
}
}
Html::back();
}
// Generate the seed template for an operation (comportamento 1.x + custom fields descobertos).
if (isset($_POST['gen_template'])) {
$op = (string) ($_POST['template_op'] ?? '');
if (in_array($op, PluginRedmineTemplateengine::OPERATIONS, true)) {
$seed = PluginRedmineTemplateengine::mergeDiscoveredCustomFields(
$op,
PluginRedmineTemplateengine::defaultTemplate($op)
);
PluginRedmineTemplateengine::save(
$op,
json_encode($seed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
false
);
Session::addMessageAfterRedirect(__('Template gerado (inativo). Revise os campos e ative quando estiver pronto.', 'redmine'));
}
Html::back();
}
// Add a manual user mapping override (GLPI user -> Redmine user).
if (isset($_POST["add_usermap"])) {
$uid = (int) ($_POST['override_users_id'] ?? 0);
$rid = (int) ($_POST['override_redmine_user_id'] ?? 0);
if ($uid > 0 && $rid > 0) {
$DB->delete('glpi_plugin_redmine_usermap', ['users_id' => $uid]); // replace existing
$DB->insert('glpi_plugin_redmine_usermap', ['users_id' => $uid, 'redmine_user_id' => $rid]);
Session::addMessageAfterRedirect(__('Mapeamento adicionado.', 'redmine'));
} else {
Session::addMessageAfterRedirect(__('Selecione um usuário GLPI e um usuário Redmine.', 'redmine'), false, ERROR);
}
Html::back();
}
// Remove a manual user mapping override.
if (isset($_POST["del_usermap"])) {
$DB->delete('glpi_plugin_redmine_usermap', ['id' => (int) $_POST['del_usermap']]);
Session::addMessageAfterRedirect(__('Mapeamento removido.', 'redmine'));
Html::back();
}
Html::header('Redmine Config', $_SERVER['PHP_SELF'], "config", "plugins");
$config->showForm(1);
Html::footer();