This commit is contained in:
Lizandro Guarnizo
2026-05-14 19:56:44 -05:00
parent a633bc765c
commit beb9e9d9eb
3 changed files with 80 additions and 39 deletions
+32
View File
File diff suppressed because one or more lines are too long
+26 -17
View File
@@ -109,24 +109,33 @@ type HostingerDNSRecord struct {
Priority int `json:"priority,omitempty"`
}
// HostingerOrder representa una orden de facturación.
type HostingerOrder struct {
ID int `json:"id"`
// HostingerSubscription representa una suscripción de facturación.
type HostingerSubscription struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
Total float64 `json:"total"`
Currency string `json:"currency"`
BillingPeriod int `json:"billing_period"`
BillingPeriodUnit string `json:"billing_period_unit"`
CurrencyCode string `json:"currency_code"`
TotalPrice int `json:"total_price"`
RenewalPrice int `json:"renewal_price"`
IsAutoRenewed bool `json:"is_auto_renewed"`
CreatedAt string `json:"created_at"`
ExpiresAt string `json:"expires_at"`
NextBillingAt string `json:"next_billing_at"`
}
// HostingerHosting representa una cuenta de hosting.
type HostingerHosting struct {
ID int `json:"id"`
Domain string `json:"domain"`
Plan string `json:"plan"`
State string `json:"state"`
ExpiresAt string `json:"expires_at"`
DiskUsed int64 `json:"disk_used"`
DiskLimit int64 `json:"disk_limit"`
VhostType string `json:"vhost_type"`
IsEnabled bool `json:"is_enabled"`
Username string `json:"username"`
ClientID int `json:"client_id"`
OrderID int `json:"order_id"`
CreatedAt string `json:"created_at"`
RootDirectory string `json:"root_directory"`
ParentDomain string `json:"parent_domain"`
}
// ─── Métodos de la API ───────────────────────────────────────────────────────
@@ -188,21 +197,21 @@ func (c *HostingerClient) GetDNSRecords(domain string) ([]HostingerDNSRecord, er
return []HostingerDNSRecord{}, nil
}
// GetOrders obtiene las órdenes de facturación.
func (c *HostingerClient) GetOrders() ([]HostingerOrder, error) {
body, err := c.getRaw(context.Background(), "/billing/v1/orders")
// GetOrders obtiene las suscripciones de facturación.
func (c *HostingerClient) GetOrders() ([]HostingerSubscription, error) {
body, err := c.getRaw(context.Background(), "/billing/v1/subscriptions")
if err != nil {
return nil, err
}
var wrapped struct {
Data []HostingerOrder `json:"data"`
Data []HostingerSubscription `json:"data"`
}
if err := json.Unmarshal(body, &wrapped); err == nil && wrapped.Data != nil {
return wrapped.Data, nil
}
var arr []HostingerOrder
var arr []HostingerSubscription
if err := json.Unmarshal(body, &arr); err != nil {
return nil, fmt.Errorf("hostinger: no se pudo interpretar respuesta orders: %w", err)
return nil, fmt.Errorf("hostinger: no se pudo interpretar respuesta subscriptions: %w", err)
}
return arr, nil
}
+19 -19
View File
@@ -71,7 +71,7 @@
<div class="flex justify-between"><span>Plan</span><span x-text="v.plan || '—'"></span></div>
<div class="flex justify-between"><span>Datacenter</span><span x-text="v.data_center || '—'"></span></div>
<div class="flex justify-between"><span>CPU</span><span x-text="(v.cpus || v.cpu || '—') + ' vCPU'"></span></div>
<div class="flex justify-between"><span>RAM</span><span x-text="formatBytes(v.ram) + ' RAM'"></span></div>
<div class="flex justify-between"><span>RAM</span><span x-text="formatBytes(v.memory) + ' RAM'"></span></div>
<div class="flex justify-between"><span>Disco</span><span x-text="formatBytes(v.disk)"></span></div>
</div>
<button @click="loadDNSForDomain(v.hostname)"
@@ -98,7 +98,7 @@
</tr>
</thead>
<tbody>
<template x-for="d in domains" :key="d.domain">
<template x-for="(d, dIdx) in domains" :key="d.domain + '_' + dIdx">
<tr class="border-b hover:bg-gray-50">
<td class="py-2 px-3 font-mono text-xs" x-text="d.domain"></td>
<td class="py-2 px-3">
@@ -129,24 +129,24 @@
<thead>
<tr class="text-left border-b text-xs text-gray-500 font-semibold">
<th class="py-2 px-3">Dominio</th>
<th class="py-2 px-3">Plan</th>
<th class="py-2 px-3">Tipo</th>
<th class="py-2 px-3">Estado</th>
<th class="py-2 px-3">Disco usado</th>
<th class="py-2 px-3">Vence</th>
<th class="py-2 px-3">Usuario</th>
<th class="py-2 px-3">Creado</th>
</tr>
</thead>
<tbody>
<template x-for="h in hosting" :key="h.id">
<template x-for="(h, hIdx) in hosting" :key="h.domain + '_' + hIdx">
<tr class="border-b hover:bg-gray-50">
<td class="py-2 px-3 font-mono text-xs" x-text="h.domain || '—'"></td>
<td class="py-2 px-3 text-xs" x-text="h.plan || '—'"></td>
<td class="py-2 px-3 text-xs" x-text="h.vhost_type || '—'"></td>
<td class="py-2 px-3">
<span class="px-2 py-0.5 rounded-full text-xs"
:class="h.state === 'active' ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'"
x-text="h.state || '—'"></span>
:class="h.is_enabled ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500'"
x-text="h.is_enabled ? 'activo' : 'inactivo'"></span>
</td>
<td class="py-2 px-3 text-xs" x-text="formatBytes(h.disk_used) + ' / ' + formatBytes(h.disk_limit)"></td>
<td class="py-2 px-3 text-xs text-gray-500" x-text="h.expires_at || '—'"></td>
<td class="py-2 px-3 text-xs" x-text="h.username || '—'"></td>
<td class="py-2 px-3 text-xs text-gray-500" x-text="h.created_at || '—'"></td>
</tr>
</template>
</tbody>
@@ -161,25 +161,25 @@
<table class="table-auto w-full text-sm">
<thead>
<tr class="text-left border-b text-xs text-gray-500 font-semibold">
<th class="py-2 px-3">ID</th>
<th class="py-2 px-3">Nombre</th>
<th class="py-2 px-3">Estado</th>
<th class="py-2 px-3">Total</th>
<th class="py-2 px-3">Precio</th>
<th class="py-2 px-3">Moneda</th>
<th class="py-2 px-3">Fecha</th>
<th class="py-2 px-3">Vence</th>
</tr>
</thead>
<tbody>
<template x-for="o in orders" :key="o.id">
<tr class="border-b hover:bg-gray-50">
<td class="py-2 px-3 text-xs font-mono" x-text="o.id"></td>
<td class="py-2 px-3 text-xs" x-text="o.name || '—'"></td>
<td class="py-2 px-3">
<span class="px-2 py-0.5 rounded-full text-xs"
:class="o.status === 'completed' ? 'bg-green-100 text-green-700' : 'bg-yellow-100 text-yellow-700'"
:class="o.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-yellow-100 text-yellow-700'"
x-text="o.status"></span>
</td>
<td class="py-2 px-3 text-xs font-semibold" x-text="o.total"></td>
<td class="py-2 px-3 text-xs" x-text="o.currency || '—'"></td>
<td class="py-2 px-3 text-xs text-gray-500" x-text="o.created_at || '—'"></td>
<td class="py-2 px-3 text-xs font-semibold" x-text="o.total_price || '—'"></td>
<td class="py-2 px-3 text-xs" x-text="o.currency_code || '—'"></td>
<td class="py-2 px-3 text-xs text-gray-500" x-text="o.expires_at || '—'"></td>
</tr>
</template>
</tbody>