146 lines
3.7 KiB
TypeScript
146 lines
3.7 KiB
TypeScript
/**
|
|
* Netlify Function: Upload Avatar
|
|
* POST /storage/v1/object/avatars/{userId}/avatar
|
|
*
|
|
* Aceita JSON com base64 para simplificar o upload via Netlify Functions
|
|
*/
|
|
|
|
import type { Handler, HandlerEvent } from "@netlify/functions";
|
|
|
|
const SUPABASE_URL = "https://yuanqfswhberkoevtmfr.supabase.co";
|
|
const SUPABASE_ANON_KEY =
|
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ";
|
|
|
|
export const handler: Handler = async (event: HandlerEvent) => {
|
|
const headers = {
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
};
|
|
|
|
if (event.httpMethod === "OPTIONS") {
|
|
return {
|
|
statusCode: 200,
|
|
headers,
|
|
body: "",
|
|
};
|
|
}
|
|
|
|
if (event.httpMethod !== "POST") {
|
|
return {
|
|
statusCode: 405,
|
|
headers,
|
|
body: JSON.stringify({ error: "Method Not Allowed" }),
|
|
};
|
|
}
|
|
|
|
try {
|
|
const authHeader =
|
|
event.headers.authorization || event.headers.Authorization;
|
|
|
|
if (!authHeader) {
|
|
return {
|
|
statusCode: 401,
|
|
headers,
|
|
body: JSON.stringify({ error: "Token não fornecido" }),
|
|
};
|
|
}
|
|
|
|
// Extrai userId do query string
|
|
const userId = event.queryStringParameters?.userId;
|
|
|
|
if (!userId) {
|
|
return {
|
|
statusCode: 400,
|
|
headers,
|
|
body: JSON.stringify({ error: "userId é obrigatório" }),
|
|
};
|
|
}
|
|
|
|
// Parse JSON body com base64
|
|
let fileData: string;
|
|
let contentType: string;
|
|
|
|
try {
|
|
const body = JSON.parse(event.body || "{}");
|
|
fileData = body.fileData; // base64 string
|
|
contentType = body.contentType || "image/jpeg";
|
|
|
|
if (!fileData) {
|
|
return {
|
|
statusCode: 400,
|
|
headers,
|
|
body: JSON.stringify({ error: "fileData (base64) é obrigatório" }),
|
|
};
|
|
}
|
|
} catch {
|
|
return {
|
|
statusCode: 400,
|
|
headers,
|
|
body: JSON.stringify({
|
|
error: "Body deve ser JSON válido com fileData em base64",
|
|
}),
|
|
};
|
|
}
|
|
|
|
// Converte base64 para Buffer
|
|
const buffer = Buffer.from(fileData, "base64");
|
|
|
|
// Upload para Supabase Storage
|
|
const response = await fetch(
|
|
`${SUPABASE_URL}/storage/v1/object/avatars/${userId}/avatar`,
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
apikey: SUPABASE_ANON_KEY,
|
|
Authorization: authHeader,
|
|
"Content-Type": contentType,
|
|
"x-upsert": "true", // Sobrescreve se já existir
|
|
},
|
|
body: buffer,
|
|
}
|
|
);
|
|
|
|
const data = await response.json();
|
|
|
|
if (!response.ok) {
|
|
console.error("Erro do Supabase:", data);
|
|
return {
|
|
statusCode: response.status,
|
|
headers: {
|
|
...headers,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
error: data.error || "Erro ao fazer upload no Supabase",
|
|
details: data,
|
|
}),
|
|
};
|
|
}
|
|
|
|
return {
|
|
statusCode: 200,
|
|
headers: {
|
|
...headers,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
message: "Upload realizado com sucesso",
|
|
path: data.Key || data.path,
|
|
fullPath: data.Key || data.path,
|
|
}),
|
|
};
|
|
} catch (error) {
|
|
console.error("Erro no upload do avatar:", error);
|
|
|
|
return {
|
|
statusCode: 500,
|
|
headers,
|
|
body: JSON.stringify({
|
|
error: "Erro interno no servidor",
|
|
message: error instanceof Error ? error.message : "Erro desconhecido",
|
|
}),
|
|
};
|
|
}
|
|
};
|