Tài liệu
Tải avatar
Tải avatar Ví dụ này tải avatar profile lên và liên kết với user_profile . Route tải lên Tạo custom route POST /profile/avatar nhận upload multipart. Handler lưu file rồi cập nhật profile của người dùng hiện tại. if (!@USER?.id) { @THROW401(); } if (!@UPLOADED_FILE) { @THROW400('
Tải avatar
Ví dụ này tải avatar profile lên và liên kết với user_profile.
Route tải lên
Tạo custom route POST /profile/avatar nhận upload multipart. Handler lưu file rồi cập nhật profile của người dùng hiện tại.
if (!@USER?.id) {
@THROW401();
}
if (!@UPLOADED_FILE) {
@THROW400('file is required');
}
const uploaded = await @STORAGE.$upload({
file: @UPLOADED_FILE,
folder: 'avatars',
isPublic: true
});
const profileResult = await #user_profile.find({
filter: { user: { id: { _eq: @USER.id } } },
fields: 'id',
limit: 1
});
const data = {
user: { id: @USER.id },
avatar: { id: uploaded.id }
};
if (profileResult.data?.[0]) {
const updated = await #user_profile.update({
id: profileResult.data[0].id,
data
});
return updated.data?.[0] || null;
}
const created = await #user_profile.create({ data });
return created.data?.[0] || null;
Request từ trình duyệt
const form = new FormData();
form.append('file', fileInput.files[0]);
const uploadId = crypto.randomUUID();
await fetch('/enfyra/profile/avatar', {
method: 'POST',
headers: { 'x-enfyra-upload-id': uploadId },
body: form,
credentials: 'include'
});
Lắng nghe $system:upload:progress trên admin socket đã xác thực và ghép event theo uploadId.
Đọc profile công khai
Chỉ mở các field an toàn.
GET /user_profile?fields=id,displayName,avatar.url