feature(up-dow-avatar): tidy avatar upload, enforce BearerAuth, add apidog types

This commit is contained in:
pedrogomes5913 2025-10-29 16:49:28 -03:00
parent 3c52ec5e3a
commit 47ef207454
4 changed files with 1138 additions and 21 deletions

View File

@ -4,6 +4,7 @@
"@heroicons/react": "^2.2.0",
"@supabase/supabase-js": "^2.75.0",
"date-fns": "^4.1.0",
"next": "^16.0.0",
"react-big-calendar": "^1.19.4",
"react-signature-canvas": "^1.1.0-alpha.2"
}

1107
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2771,30 +2771,27 @@ export async function uploadFotoPaciente(_id: string | number, _file: File): Pro
};
const ext = extMap[_file.type] || 'jpg';
// O bucket deve ser 'avatars' e o caminho do objeto será userId/avatar.ext
const bucket = 'avatars';
const objectPath = `${userId}/avatar.${ext}`;
const uploadUrl = `${ENV_CONFIG.SUPABASE_URL}/storage/v1/object/${bucket}/${encodeURIComponent(objectPath)}`;
const uploadUrl = `https://mock.apidog.com/m1/1053378-0-default/storage/v1/object/avatars/${encodeURI(objectPath)}`;
// Build multipart form data
const form = new FormData();
form.append('file', _file, `avatar.${ext}`);
const headers: Record<string, string> = {
// Supabase requires the anon key in 'apikey' header for client-side uploads
apikey: ENV_CONFIG.SUPABASE_ANON_KEY,
// Accept json
Accept: 'application/json',
Accept: 'application/json'
};
// if user is logged in, include Authorization header
const jwt = getAuthToken();
if (jwt) headers.Authorization = `Bearer ${jwt}`;
console.debug('[uploadFotoPaciente] Iniciando upload:', {
const jwt = getAuthToken();
if (!jwt) {
throw new Error('Autenticação necessária: token JWT obrigatório para upload de avatar');
}
headers.Authorization = `Bearer ${jwt}`;
console.debug('[uploadFotoPaciente] Iniciando upload:', {
url: uploadUrl,
fileType: _file.type,
fileSize: _file.size,
hasAuth: !!jwt
hasAuth: true
});
const res = await fetch(uploadUrl, {
@ -2827,7 +2824,7 @@ export async function uploadFotoPaciente(_id: string | number, _file: File): Pro
// The API may not return a structured body; return the Key we constructed
const key = (json && (json.Key || json.key)) ?? objectPath;
const publicUrl = `${ENV_CONFIG.SUPABASE_URL}/storage/v1/object/public/avatars/${encodeURIComponent(userId)}/avatar.${ext}`;
const publicUrl = `https://mock.apidog.com/m1/1053378-0-default/storage/v1/object/avatars/${encodeURIComponent(userId)}/avatar.${ext}`;
return { foto_url: publicUrl, Key: key };
}
@ -2842,21 +2839,22 @@ export function getAvatarPublicUrl(userId: string | number): string {
// Example: https://<project>.supabase.co/storage/v1/object/public/avatars/{userId}/avatar
const id = String(userId || '').trim();
if (!id) throw new Error('userId é obrigatório para obter URL pública do avatar');
const base = String(ENV_CONFIG.SUPABASE_URL).replace(/\/$/, '');
// Note: Supabase public object path does not require an extension in some setups
return `${base}/storage/v1/object/public/${encodeURIComponent('avatars')}/${encodeURIComponent(id)}/avatar`;
return `https://mock.apidog.com/m1/1053378-0-default/storage/v1/object/avatars/${encodeURIComponent(id)}/avatar`;
}
export async function removerFotoPaciente(_id: string | number): Promise<void> {
const userId = String(_id || '').trim();
if (!userId) throw new Error('ID do paciente é obrigatório para remover foto');
const deleteUrl = `${ENV_CONFIG.SUPABASE_URL}/storage/v1/object/avatars/${encodeURIComponent(userId)}/avatar`;
const objectPath = `${userId}/avatar`;
const deleteUrl = `https://mock.apidog.com/m1/1053378-0-default/storage/v1/object/avatars/${encodeURI(objectPath)}`;
const headers: Record<string,string> = {
apikey: ENV_CONFIG.SUPABASE_ANON_KEY,
Accept: 'application/json',
Accept: 'application/json'
};
// Require auth for delete (follow security expectations)
const jwt = getAuthToken();
if (jwt) headers.Authorization = `Bearer ${jwt}`;
if (!jwt) throw new Error('Autenticação necessária: token JWT obrigatório para remover avatar');
headers.Authorization = `Bearer ${jwt}`;
try {
console.debug('[removerFotoPaciente] Deleting avatar for user:', userId, 'url:', deleteUrl);

View File

@ -0,0 +1,11 @@
// Types for APIdog/OpenAPI helper models
export interface ApidogModel {
/**
* Path parameter used by the mock/OpenAPI for storage endpoints.
* Example: "user-123/avatar.jpg"
*/
path: string;
[property: string]: any;
}
export default ApidogModel;