feat: endpoints usan api_base_url como base, rutas relativas en UI
- Banner en tab Endpoints muestra la URL base de General - Inputs de URL aceptan rutas relativas (?param=x o /ruta) - Preview live de la URL completa (base+ruta) bajo cada input - Backend prepend api_base_url en test y sync si URL no es absoluta - Compatible hacia atrás: URLs absolutas existentes siguen funcionando Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
bfbc70451d
commit
43933bfe3a
@@ -1113,12 +1113,23 @@ HTML;
|
||||
$epStmt->execute([$id]);
|
||||
$allEps = $epStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
$baseRaw = rtrim($company['api_base_url'] ?? '', '/');
|
||||
$baseHtml = self::h($baseRaw);
|
||||
|
||||
$epRows = '';
|
||||
foreach ($allEps as $ep) {
|
||||
$epKey = self::h($ep['endpoint_key']);
|
||||
$epName = self::h($ep['name'] ?? '');
|
||||
$epUrl = self::h($ep['url'] ?? '');
|
||||
$epMeth = $ep['method'] ?? 'GET';
|
||||
// Preview full URL
|
||||
$rawUrl = $ep['url'] ?? '';
|
||||
if ($rawUrl === '' || str_starts_with($rawUrl, 'http')) {
|
||||
$previewUrl = self::h($rawUrl);
|
||||
} else {
|
||||
$sep = str_starts_with($rawUrl, '?') ? '' : '/';
|
||||
$previewUrl = self::h($baseRaw . $sep . ltrim($rawUrl, '/'));
|
||||
}
|
||||
$epDir = $ep['direction'] ?? 'download';
|
||||
$epParams = self::h($ep['params'] ?? '');
|
||||
$epAct = $ep['is_active'] ? 'checked' : '';
|
||||
@@ -1215,9 +1226,10 @@ VR;
|
||||
<option {$mSel('GET')}>GET</option><option {$mSel('POST')}>POST</option>
|
||||
</select>
|
||||
</td>
|
||||
<td style="min-width:200px">
|
||||
<input type="text" value="{$epUrl}" id="epu_{$epId}" placeholder="https://..." oninput="onUrlChange({$epId})" style="width:100%;font-size:12px;padding:4px 6px;border:1px solid #e5e7eb;border-radius:4px">
|
||||
<div style="font-size:10px;color:#9ca3af;margin-top:2px">Usa {'{var}'} para variables. {$lastAt}</div>
|
||||
<td style="min-width:220px">
|
||||
<input type="text" value="{$epUrl}" id="epu_{$epId}" placeholder="?peticion=xxx o /ruta" oninput="onUrlChange({$epId})" style="width:100%;font-size:12px;padding:4px 6px;border:1px solid #e5e7eb;border-radius:4px">
|
||||
<div id="ep-preview-{$epId}" style="font-size:10px;color:#6b7280;font-family:monospace;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="{$previewUrl}">{$previewUrl}</div>
|
||||
<div style="font-size:10px;color:#9ca3af;margin-top:1px">Usa {'{var}'} para variables. {$lastAt}</div>
|
||||
</td>
|
||||
<td><input type="checkbox" {$epAct} id="epa_{$epId}" title="Activo"></td>
|
||||
<td style="white-space:nowrap">
|
||||
@@ -1246,15 +1258,21 @@ ROW;
|
||||
|
||||
$epHtml = <<<EP
|
||||
<div class="card-h" style="margin-bottom:12px">🔌 Endpoints API</div>
|
||||
<div style="background:#fffbeb;border:1px solid #fde68a;border-radius:8px;padding:10px 14px;margin-bottom:14px;font-size:12px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
|
||||
<span>🔗 <strong>URL base:</strong></span>
|
||||
<code style="background:#fff8e1;padding:2px 6px;border-radius:4px;font-size:12px">{$baseHtml}</code>
|
||||
<a href="/admin/company/edit?id={$id}&tab=general" style="color:#1e40af;font-size:11px">cambiar en General →</a>
|
||||
<span style="color:#92400e;font-size:11px">· Los endpoints usan rutas relativas a esta URL</span>
|
||||
</div>
|
||||
<p style="font-size:12px;color:#7a8291;margin-bottom:14px">
|
||||
Define los endpoints del ERP. Usa <code>{'{variable}'}</code> en la URL para variables que el bot pedirá al usuario.<br>
|
||||
Ejemplo: <code>?peticion=produccion&desde={'{desde}'}&hasta={'{hasta}'}</code>
|
||||
Escribe solo la ruta o sufijo: <code>?peticion=produccion</code> o <code>/mi/ruta</code>. Se combina con la URL base.<br>
|
||||
Usa <code>{'{variable}'}</code> para variables que el bot pedirá al usuario. Ejemplo: <code>?desde={'{desde}'}&hasta={'{hasta}'}</code>
|
||||
</p>
|
||||
<div class="card" style="overflow-x:auto">
|
||||
<table style="width:100%;min-width:700px">
|
||||
<thead>
|
||||
<tr style="font-size:12px;text-align:left">
|
||||
<th>Key</th><th>Nombre</th><th>Dirección</th><th>Método</th><th>URL</th><th>Activo</th><th></th>
|
||||
<th>Key</th><th>Nombre</th><th>Dirección</th><th>Método</th><th>Ruta / sufijo</th><th>Activo</th><th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="epTableBody">{$epRows}</tbody>
|
||||
@@ -1290,8 +1308,9 @@ ROW;
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>URL</label>
|
||||
<input type="text" id="newEpUrl" placeholder="https://app.palmas360.com/...?peticion=xxx">
|
||||
<label>Ruta / sufijo</label>
|
||||
<input type="text" id="newEpUrl" placeholder="?peticion=xxx o /mi/ruta" oninput="updateNewEpPreview()">
|
||||
<div id="newEpPreview" style="font-size:11px;color:#6b7280;font-family:monospace;margin-top:4px"></div>
|
||||
</div>
|
||||
<div id="newEpMsg" style="margin-bottom:8px"></div>
|
||||
<button class="btn-primary" onclick="addNewEp({$id})">Agregar</button>
|
||||
@@ -1620,8 +1639,33 @@ function collectVarConfigs(epId) {
|
||||
return JSON.stringify(configs);
|
||||
}
|
||||
|
||||
const BASE_URL = '{$baseHtml}';
|
||||
|
||||
function buildFullUrl(path) {
|
||||
if (!path || path.startsWith('http')) return path;
|
||||
const base = BASE_URL.replace(/\/$/, '');
|
||||
const sep = path.startsWith('?') ? '' : '/';
|
||||
return base + sep + path.replace(/^\//, '');
|
||||
}
|
||||
|
||||
function updateEpPreview(epId) {
|
||||
const path = document.getElementById('epu_'+epId)?.value || '';
|
||||
const el = document.getElementById('ep-preview-'+epId);
|
||||
if (!el) return;
|
||||
const full = buildFullUrl(path);
|
||||
el.textContent = full || '';
|
||||
el.title = full || '';
|
||||
}
|
||||
|
||||
function updateNewEpPreview() {
|
||||
const path = document.getElementById('newEpUrl')?.value || '';
|
||||
const el = document.getElementById('newEpPreview');
|
||||
if (el) el.textContent = buildFullUrl(path) || '';
|
||||
}
|
||||
|
||||
// When URL changes, refresh the vars section
|
||||
function onUrlChange(epId) {
|
||||
updateEpPreview(epId);
|
||||
const url = document.getElementById('epu_'+epId).value;
|
||||
const matches = [...url.matchAll(/\{([^}]+)\}/g)].map(m => m[1]);
|
||||
const vrRows = document.getElementById('vr-rows-'+epId);
|
||||
@@ -1797,9 +1841,15 @@ HTML;
|
||||
exit;
|
||||
}
|
||||
|
||||
// Llamar al endpoint
|
||||
// Llamar al endpoint — prepend base URL si es ruta relativa
|
||||
$epUrl = $ep['url'];
|
||||
if (!str_starts_with($epUrl, 'http')) {
|
||||
$base = rtrim($company['api_base_url'] ?? '', '/');
|
||||
$sep = str_starts_with($epUrl, '?') ? '' : '/';
|
||||
$epUrl = $base . $sep . ltrim($epUrl, '/');
|
||||
}
|
||||
$apiKey = $company['api_key'] ?? '';
|
||||
$ch = curl_init($ep['url']);
|
||||
$ch = curl_init($epUrl);
|
||||
$opts = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
@@ -2050,6 +2100,13 @@ HTML;
|
||||
$company = CompanyRepository::findById($companyId);
|
||||
$apiKey = $company['api_key'] ?? '';
|
||||
|
||||
// Prepend api_base_url for relative paths
|
||||
if ($url !== '' && !str_starts_with($url, 'http')) {
|
||||
$base = rtrim($company['api_base_url'] ?? '', '/');
|
||||
$sep = str_starts_with($url, '?') ? '' : '/';
|
||||
$url = $base . $sep . ltrim($url, '/');
|
||||
}
|
||||
|
||||
$ch = curl_init($url);
|
||||
$opts = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
|
||||
Reference in New Issue
Block a user