Files
prowler/ui/actions/integrations/integrations.ts
T

320 lines
8.9 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import {
apiBaseUrl,
getAuthHeaders,
handleApiError,
parseStringify,
} from "@/lib";
import { getTask } from "../task";
export const getIntegrations = async (searchParams?: URLSearchParams) => {
const headers = await getAuthHeaders({ contentType: false });
const url = new URL(`${apiBaseUrl}/integrations`);
if (searchParams) {
searchParams.forEach((value, key) => {
url.searchParams.append(key, value);
});
}
try {
const response = await fetch(url.toString(), { method: "GET", headers });
if (response.ok) {
const data = await response.json();
return parseStringify(data);
}
console.error(`Failed to fetch integrations: ${response.statusText}`);
return { data: [], meta: { pagination: { count: 0 } } };
} catch (error) {
console.error("Error fetching integrations:", error);
return { data: [], meta: { pagination: { count: 0 } } };
}
};
export const getIntegration = async (id: string) => {
const headers = await getAuthHeaders({ contentType: false });
const url = new URL(`${apiBaseUrl}/integrations/${id}`);
try {
const response = await fetch(url.toString(), { method: "GET", headers });
if (response.ok) {
const data = await response.json();
return parseStringify(data);
}
console.error(`Failed to fetch integration: ${response.statusText}`);
return null;
} catch (error) {
console.error("Error fetching integration:", error);
return null;
}
};
export const createIntegration = async (
formData: FormData,
): Promise<{ success: string; testConnection?: any } | { error: string }> => {
const headers = await getAuthHeaders({ contentType: true });
const url = new URL(`${apiBaseUrl}/integrations`);
try {
const integration_type = formData.get("integration_type") as string;
const configuration = JSON.parse(formData.get("configuration") as string);
const credentials = JSON.parse(formData.get("credentials") as string);
const providers = JSON.parse(formData.get("providers") as string);
const enabled = formData.get("enabled")
? JSON.parse(formData.get("enabled") as string)
: true;
const integrationData = {
data: {
type: "integrations",
attributes: { integration_type, configuration, credentials, enabled },
relationships: {
providers: {
data: providers.map((providerId: string) => ({
id: providerId,
type: "providers",
})),
},
},
},
};
const response = await fetch(url.toString(), {
method: "POST",
headers,
body: JSON.stringify(integrationData),
});
if (response.ok) {
const responseData = await response.json();
const integrationId = responseData.data.id;
const testResult = await testIntegrationConnection(integrationId);
return {
success: "Integration created successfully!",
testConnection: testResult,
};
}
const errorData = await response.json().catch(() => ({}));
const errorMessage =
errorData.errors?.[0]?.detail ||
`Unable to create S3 integration: ${response.statusText}`;
return { error: errorMessage };
} catch (error) {
return handleApiError(error);
}
};
export const updateIntegration = async (id: string, formData: FormData) => {
const headers = await getAuthHeaders({ contentType: true });
const url = new URL(`${apiBaseUrl}/integrations/${id}`);
try {
const integration_type = formData.get("integration_type") as string;
const configuration = formData.get("configuration")
? JSON.parse(formData.get("configuration") as string)
: undefined;
const credentials = formData.get("credentials")
? JSON.parse(formData.get("credentials") as string)
: undefined;
const providers = formData.get("providers")
? JSON.parse(formData.get("providers") as string)
: undefined;
const enabled = formData.get("enabled")
? JSON.parse(formData.get("enabled") as string)
: undefined;
const integrationData: any = {
data: {
type: "integrations",
id,
attributes: { integration_type },
},
};
if (configuration) {
integrationData.data.attributes.configuration = configuration;
}
if (credentials) {
integrationData.data.attributes.credentials = credentials;
}
if (enabled !== undefined) {
integrationData.data.attributes.enabled = enabled;
}
if (providers) {
integrationData.data.relationships = {
providers: {
data: providers.map((providerId: string) => ({
id: providerId,
type: "providers",
})),
},
};
}
const response = await fetch(url.toString(), {
method: "PATCH",
headers,
body: JSON.stringify(integrationData),
});
if (response.ok) {
revalidatePath("/integrations/s3");
// Only test connection if credentials or configuration were updated
if (credentials || configuration) {
const testResult = await testIntegrationConnection(id);
return {
success: "Integration updated successfully!",
testConnection: testResult,
};
} else {
return {
success: "Integration updated successfully!",
};
}
}
const errorData = await response.json().catch(() => ({}));
const errorMessage =
errorData.errors?.[0]?.detail ||
`Unable to update S3 integration: ${response.statusText}`;
return { error: errorMessage };
} catch (error) {
return handleApiError(error);
}
};
export const deleteIntegration = async (id: string) => {
const headers = await getAuthHeaders({ contentType: true });
const url = new URL(`${apiBaseUrl}/integrations/${id}`);
try {
const response = await fetch(url.toString(), { method: "DELETE", headers });
if (response.ok) {
revalidatePath("/integrations/s3");
return { success: "Integration deleted successfully!" };
}
const errorData = await response.json().catch(() => ({}));
const errorMessage =
errorData.errors?.[0]?.detail ||
`Unable to delete S3 integration: ${response.statusText}`;
return { error: errorMessage };
} catch (error) {
return handleApiError(error);
}
};
const pollTaskUntilComplete = async (taskId: string): Promise<any> => {
const maxAttempts = 10;
let attempts = 0;
while (attempts < maxAttempts) {
try {
const taskResponse = await getTask(taskId);
if (taskResponse.error) {
return { error: taskResponse.error };
}
const task = taskResponse.data;
const taskState = task?.attributes?.state;
// Continue polling while task is executing
if (taskState === "executing") {
await new Promise((resolve) => setTimeout(resolve, 3000));
attempts++;
continue;
}
const result = task?.attributes?.result;
const isSuccessful =
taskState === "completed" &&
result?.connected === true &&
result?.error === null;
let message;
if (isSuccessful) {
message = "Connection test completed successfully.";
} else {
message = result?.error || "Connection test failed.";
}
return {
success: isSuccessful,
message,
taskState,
result,
};
} catch (error) {
return { error: "Failed to monitor connection test." };
}
}
return { error: "Connection test timeout. Test took too long to complete." };
};
export const testIntegrationConnection = async (id: string) => {
const headers = await getAuthHeaders({ contentType: true });
const url = new URL(`${apiBaseUrl}/integrations/${id}/connection`);
try {
const response = await fetch(url.toString(), { method: "POST", headers });
if (response.ok) {
const data = await response.json();
const taskId = data?.data?.id;
if (taskId) {
// Poll the task until completion
const pollResult = await pollTaskUntilComplete(taskId);
revalidatePath("/integrations/s3");
if (pollResult.error) {
return { error: pollResult.error };
}
if (pollResult.success) {
return {
success: "Connection test completed successfully!",
message: pollResult.message,
data: parseStringify(data),
};
} else {
return {
error: pollResult.message || "Connection test failed.",
};
}
} else {
return {
error: "Failed to start connection test. No task ID received.",
};
}
}
const errorData = await response.json().catch(() => ({}));
const errorMessage =
errorData.errors?.[0]?.detail ||
`Unable to test S3 integration connection: ${response.statusText}`;
return { error: errorMessage };
} catch (error) {
return handleApiError(error);
}
};