All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 2m37s
- Implementar UTabs (Contactos, Aplicaciones, Perfil) en app.vue - Crear componentes ContactsList, ContactsFilters, ContactItem - Agregar server routes para obtener contactos via Metabase API - Sistema de aliases por usuario guardados en archivos JSON - Filtros: nombre (fuzzy search), ID, teléfono, empleado - Click en contacto abre WhatsApp - Estilo glassmorphism consistente con la app
112 lines
3.0 KiB
TypeScript
112 lines
3.0 KiB
TypeScript
/**
|
|
* API endpoint para obtener contactos desde Metabase
|
|
* Consulta la tabla Clientes del proyecto facturador en Supabase via Metabase API
|
|
*/
|
|
|
|
interface Contact {
|
|
id: number
|
|
name: string
|
|
cedula: number | null
|
|
ubicacion: string | null
|
|
grupo_estudio: string | null
|
|
empleado: boolean
|
|
avatar_url: string | null
|
|
telefono: string | null
|
|
idciat: string | null
|
|
}
|
|
|
|
interface MetabaseResponse {
|
|
data: {
|
|
cols: Array<{ name: string }>
|
|
rows: Array<Array<unknown>>
|
|
}
|
|
}
|
|
|
|
export default defineEventHandler(async (event): Promise<Contact[]> => {
|
|
const config = useRuntimeConfig()
|
|
const headers = getRequestHeaders(event)
|
|
const query = getQuery(event)
|
|
|
|
// Verificar autenticación
|
|
const uid = headers['x-authentik-uid']
|
|
if (!uid) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
message: 'Usuario no autenticado'
|
|
})
|
|
}
|
|
|
|
// Obtener configuración de Metabase
|
|
const metabaseUrl = config.metabaseApiUrl as string
|
|
const metabaseApiKey = config.metabaseApiKey as string
|
|
const databaseId = config.metabaseDatabaseId as number
|
|
const tableId = config.metabaseTableId as number
|
|
|
|
if (!metabaseApiKey) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
message: 'API Key de Metabase no configurada'
|
|
})
|
|
}
|
|
|
|
// Construir filtros para la query
|
|
const filters: unknown[] = []
|
|
|
|
// Filtro de empleados (por defecto true)
|
|
const empleadoFilter = query.empleado !== 'false'
|
|
if (empleadoFilter) {
|
|
filters.push(['=', ['field', 'empleado', { 'base-type': 'type/Boolean' }], true])
|
|
}
|
|
|
|
// Filtro por ID exacto
|
|
if (query.id) {
|
|
const idNum = parseInt(query.id as string)
|
|
if (!isNaN(idNum)) {
|
|
filters.push(['=', ['field', 'id', { 'base-type': 'type/BigInteger' }], idNum])
|
|
}
|
|
}
|
|
|
|
// Construir la query para Metabase
|
|
const metabaseQuery = {
|
|
database: databaseId,
|
|
type: 'query',
|
|
query: {
|
|
'source-table': tableId,
|
|
'order-by': [['asc', ['field', 'id', { 'base-type': 'type/BigInteger' }]]],
|
|
filter: filters.length > 0
|
|
? (filters.length === 1 ? filters[0] : ['and', ...filters])
|
|
: undefined
|
|
}
|
|
}
|
|
|
|
try {
|
|
const response = await $fetch<MetabaseResponse>(`${metabaseUrl}/api/dataset`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-API-Key': metabaseApiKey,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: metabaseQuery
|
|
})
|
|
|
|
// Mapear columnas a objetos
|
|
const cols = response.data.cols.map((col) => col.name)
|
|
const contacts: Contact[] = response.data.rows.map((row) => {
|
|
const contact: Record<string, unknown> = {}
|
|
cols.forEach((colName, index) => {
|
|
contact[colName] = row[index]
|
|
})
|
|
return contact as unknown as Contact
|
|
})
|
|
|
|
return contacts
|
|
} catch (error: unknown) {
|
|
console.error('Error al obtener contactos de Metabase:', error)
|
|
const err = error as { statusCode?: number; message?: string }
|
|
throw createError({
|
|
statusCode: err.statusCode || 500,
|
|
message: err.message || 'Error al obtener los contactos'
|
|
})
|
|
}
|
|
})
|