modulo de agente pessoal de IA
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
/**
|
||||
* Serviço para integração com API do Asana
|
||||
*/
|
||||
|
||||
/**
|
||||
* Interface para workspace do Asana (resposta da API)
|
||||
*/
|
||||
export interface AsanaWorkspaceResponse {
|
||||
gid: string;
|
||||
resource_type: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para resposta da API de workspaces
|
||||
*/
|
||||
export interface AsanaWorkspacesResponse {
|
||||
data: AsanaWorkspaceResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para workspace formatado (usado no componente)
|
||||
*/
|
||||
export interface AsanaWorkspace {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para usuário do Asana (resposta da API)
|
||||
*/
|
||||
export interface AsanaUserResponse {
|
||||
gid: string;
|
||||
name: string;
|
||||
resource_type: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para resposta da API de usuários
|
||||
*/
|
||||
export interface AsanaUsersResponse {
|
||||
data: AsanaUserResponse[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para usuário formatado (usado no componente)
|
||||
*/
|
||||
export interface AsanaUser {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para resposta da API de integração do Asana
|
||||
*/
|
||||
export interface AsanaIntegrationResponse {
|
||||
success: boolean;
|
||||
integracao_id?: string;
|
||||
id?: string;
|
||||
api_key?: string;
|
||||
workspace_gid?: string;
|
||||
workspace_nome?: string;
|
||||
usuario_asana_gid?: string;
|
||||
usuario_asana_nome?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface para request de criação/atualização de integração
|
||||
*/
|
||||
export interface AsanaIntegrationRequest {
|
||||
user_id?: string;
|
||||
api_key: string;
|
||||
workspace_gid: string;
|
||||
workspace_nome: string;
|
||||
usuario_asana_gid: string;
|
||||
usuario_asana_nome: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serviço para integração com Asana
|
||||
*/
|
||||
class AsanaService {
|
||||
private readonly BASE_URL = 'https://app.asana.com/api/1.0';
|
||||
private readonly INTEGRATION_BASE_URL = 'https://prod-hgtx-intelligence-n8n.hgtx.com.br';
|
||||
private readonly INTEGRATION_WEBHOOK_ID = 'c898beff-84cb-44df-a69c-6eff27ccd7aa';
|
||||
|
||||
/**
|
||||
* Lista os workspaces do Asana usando o token fornecido
|
||||
*
|
||||
* @param token - Token de acesso do Asana
|
||||
* @returns Promise com a lista de workspaces formatados
|
||||
*/
|
||||
async getWorkspaces(token: string): Promise<AsanaWorkspace[]> {
|
||||
if (!token || token.trim().length === 0) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Token do Asana é obrigatório',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const axios = (await import('axios')).default;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'accept': 'application/json',
|
||||
'authorization': `Bearer ${token.trim()}`,
|
||||
};
|
||||
|
||||
const response = await axios.get<AsanaWorkspacesResponse>(
|
||||
`${this.BASE_URL}/workspaces`,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
// Converte a resposta da API para o formato esperado pelo componente
|
||||
// A API retorna gid, mas o componente espera id
|
||||
return response.data.data.map((workspace) => ({
|
||||
id: workspace.gid,
|
||||
name: workspace.name,
|
||||
}));
|
||||
} catch (error: unknown) {
|
||||
console.error('Erro ao buscar workspaces do Asana:', error);
|
||||
|
||||
// Retorna o erro da API se existir
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as { response?: { data?: any; status?: number } };
|
||||
|
||||
if (axiosError.response?.status === 401) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Token inválido ou expirado. Verifique sua chave de API.',
|
||||
};
|
||||
}
|
||||
|
||||
if (axiosError.response?.data) {
|
||||
throw {
|
||||
success: false,
|
||||
message: axiosError.response.data.message || 'Erro ao buscar workspaces do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'Erro ao buscar workspaces do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista os usuários de um workspace do Asana
|
||||
*
|
||||
* @param token - Token de acesso do Asana
|
||||
* @param workspaceId - ID do workspace (gid)
|
||||
* @returns Promise com a lista de usuários formatados
|
||||
*/
|
||||
async getUsers(token: string, workspaceId: string): Promise<AsanaUser[]> {
|
||||
if (!token || token.trim().length === 0) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Token do Asana é obrigatório',
|
||||
};
|
||||
}
|
||||
|
||||
if (!workspaceId || workspaceId.trim().length === 0) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'ID do workspace é obrigatório',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const axios = (await import('axios')).default;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'accept': 'application/json',
|
||||
'authorization': `Bearer ${token.trim()}`,
|
||||
};
|
||||
|
||||
const response = await axios.get<AsanaUsersResponse>(
|
||||
`${this.BASE_URL}/users?workspace=${workspaceId}`,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
// Converte a resposta da API para o formato esperado pelo componente
|
||||
// A API retorna gid, mas o componente espera id
|
||||
return response.data.data.map((user) => ({
|
||||
id: user.gid,
|
||||
name: user.name,
|
||||
}));
|
||||
} catch (error: unknown) {
|
||||
console.error('Erro ao buscar usuários do Asana:', error);
|
||||
|
||||
// Retorna o erro da API se existir
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as { response?: { data?: any; status?: number } };
|
||||
|
||||
if (axiosError.response?.status === 401) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Token inválido ou expirado. Verifique sua chave de API.',
|
||||
};
|
||||
}
|
||||
|
||||
if (axiosError.response?.data) {
|
||||
throw {
|
||||
success: false,
|
||||
message: axiosError.response.data.message || 'Erro ao buscar usuários do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'Erro ao buscar usuários do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtém os detalhes da integração do Asana do usuário
|
||||
*
|
||||
* @param userId - ID do usuário
|
||||
* @returns Promise com os detalhes da integração ou null se não houver
|
||||
*/
|
||||
async getIntegration(userId: string): Promise<AsanaIntegrationResponse | null> {
|
||||
if (!userId || userId.trim().length === 0) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'ID do usuário é obrigatório',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const axios = (await import('axios')).default;
|
||||
const { GlobalFunctions } = await import('@/GlobalFunctions');
|
||||
|
||||
// Obtém o token JWT para autenticação
|
||||
const token = await GlobalFunctions.getToken();
|
||||
const apiKey = import.meta.env.VITE_API_KEY || '';
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'accept': 'application/json',
|
||||
};
|
||||
|
||||
// Adiciona API key (obrigatória)
|
||||
if (apiKey) {
|
||||
headers['apikey'] = apiKey;
|
||||
}
|
||||
|
||||
// Adiciona token JWT se disponível
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// Em desenvolvimento, usa proxy do Vite para evitar CORS
|
||||
const baseUrl = import.meta.env.DEV
|
||||
? '/api/intelligence'
|
||||
: this.INTEGRATION_BASE_URL;
|
||||
|
||||
const response = await axios.get<AsanaIntegrationResponse>(
|
||||
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${userId}`,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
// Se success é false, retorna null (não tem integração)
|
||||
if (!response.data.success) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error: unknown) {
|
||||
console.error('Erro ao buscar integração do Asana:', error);
|
||||
|
||||
// Se o erro for 404 ou similar, significa que não tem integração cadastrada
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as { response?: { status?: number } };
|
||||
if (axiosError.response?.status === 404) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Para outros erros, retorna null silenciosamente (não quebra a aplicação)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cria uma nova integração do Asana
|
||||
*
|
||||
* @param request - Dados da integração a ser criada
|
||||
* @returns Promise com a resposta da criação
|
||||
*/
|
||||
async createIntegration(request: AsanaIntegrationRequest): Promise<AsanaIntegrationResponse> {
|
||||
if (!request.user_id || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Dados incompletos para criar integração',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const axios = (await import('axios')).default;
|
||||
const { GlobalFunctions } = await import('@/GlobalFunctions');
|
||||
|
||||
// Obtém o token JWT para autenticação
|
||||
const token = await GlobalFunctions.getToken();
|
||||
const apiKey = import.meta.env.VITE_API_KEY || '';
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'accept': 'application/json',
|
||||
};
|
||||
|
||||
// Adiciona API key (obrigatória)
|
||||
if (apiKey) {
|
||||
headers['apikey'] = apiKey;
|
||||
}
|
||||
|
||||
// Adiciona token JWT se disponível
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// Em desenvolvimento, usa proxy do Vite para evitar CORS
|
||||
const baseUrl = import.meta.env.DEV
|
||||
? '/api/intelligence'
|
||||
: this.INTEGRATION_BASE_URL;
|
||||
|
||||
const response = await axios.post<AsanaIntegrationResponse>(
|
||||
`${baseUrl}/webhook/codex/agente-pessoal/integracoes/asana`,
|
||||
request,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
return response.data;
|
||||
} catch (error: unknown) {
|
||||
console.error('Erro ao criar integração do Asana:', error);
|
||||
|
||||
// Retorna o erro da API se existir
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as { response?: { data?: any; status?: number } };
|
||||
|
||||
if (axiosError.response?.data) {
|
||||
const errorData = axiosError.response.data;
|
||||
throw {
|
||||
success: false,
|
||||
message: errorData.message || 'Erro ao criar integração do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'Erro ao criar integração do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Atualiza uma integração existente do Asana
|
||||
*
|
||||
* @param integracaoId - ID da integração a ser atualizada
|
||||
* @param request - Dados da integração a ser atualizada
|
||||
* @returns Promise com a resposta da atualização
|
||||
*/
|
||||
async updateIntegration(integracaoId: string, request: Omit<AsanaIntegrationRequest, 'user_id'>): Promise<AsanaIntegrationResponse> {
|
||||
if (!integracaoId || !request.api_key || !request.workspace_gid || !request.usuario_asana_gid) {
|
||||
throw {
|
||||
success: false,
|
||||
message: 'Dados incompletos para atualizar integração',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const axios = (await import('axios')).default;
|
||||
const { GlobalFunctions } = await import('@/GlobalFunctions');
|
||||
|
||||
// Obtém o token JWT para autenticação
|
||||
const token = await GlobalFunctions.getToken();
|
||||
const apiKey = import.meta.env.VITE_API_KEY || '';
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'accept': 'application/json',
|
||||
};
|
||||
|
||||
// Adiciona API key (obrigatória)
|
||||
if (apiKey) {
|
||||
headers['apikey'] = apiKey;
|
||||
}
|
||||
|
||||
// Adiciona token JWT se disponível
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
// Em desenvolvimento, usa proxy do Vite para evitar CORS
|
||||
const baseUrl = import.meta.env.DEV
|
||||
? '/api/intelligence'
|
||||
: this.INTEGRATION_BASE_URL;
|
||||
|
||||
const response = await axios.put<AsanaIntegrationResponse>(
|
||||
`${baseUrl}/webhook/${this.INTEGRATION_WEBHOOK_ID}/codex/agente-pessoal/integracoes/asana/${integracaoId}`,
|
||||
request,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
return response.data;
|
||||
} catch (error: unknown) {
|
||||
console.error('Erro ao atualizar integração do Asana:', error);
|
||||
|
||||
// Retorna o erro da API se existir
|
||||
if (error && typeof error === 'object' && 'response' in error) {
|
||||
const axiosError = error as { response?: { data?: any; status?: number } };
|
||||
|
||||
if (axiosError.response?.data) {
|
||||
const errorData = axiosError.response.data;
|
||||
throw {
|
||||
success: false,
|
||||
message: errorData.message || 'Erro ao atualizar integração do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : 'Erro ao atualizar integração do Asana',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exporta instância única (Singleton)
|
||||
export const asanaService = new AsanaService();
|
||||
Reference in New Issue
Block a user