2025-10-24 16:10:59 +02:00
|
|
|
import z from "zod";
|
2025-10-20 16:22:20 +02:00
|
|
|
import { env } from "~/env";
|
2025-10-24 16:10:59 +02:00
|
|
|
|
|
|
|
|
const FileMetadataSchema = z.object({
|
|
|
|
|
id: z.string(),
|
|
|
|
|
originalName: z.string(),
|
|
|
|
|
size: z.number(),
|
|
|
|
|
mimeType: z.string(),
|
|
|
|
|
blockCount: z.number(),
|
|
|
|
|
uploadedAt: z.string(),
|
|
|
|
|
expiresAt: z.string().nullable(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type FileMetadata = z.infer<typeof FileMetadataSchema>;
|
|
|
|
|
|
|
|
|
|
export type FileMetadataWithAdmin = FileMetadata & {
|
|
|
|
|
from_admin: boolean;
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
2025-10-24 16:10:59 +02:00
|
|
|
// Helper to fetch the list of all files
|
|
|
|
|
export async function fetchFiles(): Promise<FileMetadata[]> {
|
2025-08-28 18:27:07 +02:00
|
|
|
try {
|
2025-10-24 16:10:59 +02:00
|
|
|
const response = await fetch(
|
2025-10-27 17:58:42 +01:00
|
|
|
`${env.STORAGE_URL}/bucket/storage?token=${env.STORAGE_TOKEN}`,
|
2025-10-24 16:10:59 +02:00
|
|
|
);
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
console.error("Failed to fetch file list:", response.statusText);
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
const parse = FileMetadataSchema.array().safeParse(await response.json());
|
|
|
|
|
|
|
|
|
|
if (parse.success) {
|
|
|
|
|
return parse.data;
|
|
|
|
|
}
|
|
|
|
|
console.error("Failed to parse file metadata:", parse.error);
|
|
|
|
|
return [];
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error fetching file list:", error);
|
|
|
|
|
return [];
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-10-24 16:10:59 +02:00
|
|
|
}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-10-24 16:10:59 +02:00
|
|
|
export async function getFileInfo(id: string): Promise<FileMetadata | null> {
|
2025-08-28 18:27:07 +02:00
|
|
|
try {
|
2025-10-24 16:10:59 +02:00
|
|
|
const response = await fetch(
|
|
|
|
|
`${env.STORAGE_URL}/info/${id}?token=${env.STORAGE_TOKEN}`,
|
|
|
|
|
);
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
console.error("Failed to fetch file list:", response.statusText);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
const parse = FileMetadataSchema.safeParse(await response.json());
|
|
|
|
|
|
|
|
|
|
if (parse.success) {
|
|
|
|
|
return parse.data;
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-10-24 16:10:59 +02:00
|
|
|
console.error("Failed to parse file metadata:", parse.error);
|
|
|
|
|
return null;
|
2025-08-28 18:27:07 +02:00
|
|
|
} catch (error) {
|
2025-10-24 16:10:59 +02:00
|
|
|
console.error("Error fetching file list:", error);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type EditResponse =
|
|
|
|
|
| {
|
|
|
|
|
success: true;
|
|
|
|
|
id: string;
|
|
|
|
|
}
|
|
|
|
|
| {
|
|
|
|
|
success: false;
|
|
|
|
|
error: string;
|
|
|
|
|
};
|
|
|
|
|
export async function editFile(
|
|
|
|
|
id: string,
|
|
|
|
|
filename?: string,
|
|
|
|
|
expiresAt?: string,
|
|
|
|
|
): Promise<EditResponse> {
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append("id", id);
|
|
|
|
|
if (expiresAt) {
|
|
|
|
|
formData.append("expires_at", expiresAt);
|
|
|
|
|
}
|
|
|
|
|
if (filename) {
|
|
|
|
|
formData.append("filename", filename);
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
try {
|
2025-10-24 16:10:59 +02:00
|
|
|
const response = await fetch(
|
|
|
|
|
`${env.STORAGE_URL}/edit?token=${env.STORAGE_TOKEN}`,
|
|
|
|
|
{
|
|
|
|
|
method: "POST",
|
|
|
|
|
body: formData,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
const res = await response.json();
|
|
|
|
|
const parsed = z
|
|
|
|
|
.object({
|
|
|
|
|
id: z.string(),
|
|
|
|
|
})
|
|
|
|
|
.parse(res);
|
|
|
|
|
const fileID = parsed.id;
|
2026-02-24 15:18:59 +01:00
|
|
|
|
2025-10-24 16:10:59 +02:00
|
|
|
return { success: true, id: fileID };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
error: `Modifica fallita con status: ${response.status}`,
|
|
|
|
|
};
|
2025-08-28 18:27:07 +02:00
|
|
|
} catch (e) {
|
2025-10-24 16:10:59 +02:00
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
error: `Errore Modifica file: ${(e as Error).message}`,
|
|
|
|
|
};
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-10-24 16:10:59 +02:00
|
|
|
}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-10-24 16:10:59 +02:00
|
|
|
type DeleteResponse =
|
|
|
|
|
| {
|
|
|
|
|
success: true;
|
|
|
|
|
}
|
|
|
|
|
| {
|
|
|
|
|
success: false;
|
|
|
|
|
error: string;
|
|
|
|
|
};
|
|
|
|
|
// Helper to handle file deletion
|
|
|
|
|
export async function deleteFile(fileID: string): Promise<DeleteResponse> {
|
2025-08-28 18:27:07 +02:00
|
|
|
try {
|
2025-10-24 16:10:59 +02:00
|
|
|
// The Go server accepts POST with form data for delete
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`${env.STORAGE_URL}/delete/${fileID}?token=${env.STORAGE_TOKEN}`,
|
|
|
|
|
{
|
|
|
|
|
method: "DELETE",
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Treat redirect as success
|
|
|
|
|
if (response.ok || (response.status >= 300 && response.status < 400)) {
|
|
|
|
|
return { success: true };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
error: `Eliminazione fallita con status: ${response.status}`,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error during file deletion:", error);
|
|
|
|
|
return { success: false, error: (error as Error).message };
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-10-24 16:10:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// export const handleDownload = async (file: FileMetadata) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const response = await fetch(
|
|
|
|
|
// `${env.STORAGE_URL}/get/${file.id}?token=${env.STORAGE_TOKEN}&mode=download`,
|
|
|
|
|
// );
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-10-24 16:10:59 +02:00
|
|
|
// if (!response.ok) {
|
|
|
|
|
// throw new Error("File fetch failed");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const blob = await response.blob();
|
|
|
|
|
// const url = window.URL.createObjectURL(blob);
|
|
|
|
|
// const a = document.createElement("a");
|
|
|
|
|
// a.href = url;
|
|
|
|
|
// a.download = file.originalName;
|
|
|
|
|
// document.body.appendChild(a);
|
|
|
|
|
// a.click();
|
|
|
|
|
// a.remove();
|
|
|
|
|
// window.URL.revokeObjectURL(url);
|
|
|
|
|
// } catch {
|
|
|
|
|
// throw new Error("File download failed");
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
const safeRetrive = z.object({
|
|
|
|
|
available: z.array(FileMetadataSchema),
|
|
|
|
|
unavailable: z.array(z.string()),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export async function retriveFilesSafely(ids: string[]) {
|
2025-08-28 18:27:07 +02:00
|
|
|
try {
|
2025-10-24 16:10:59 +02:00
|
|
|
const response = await fetch(
|
|
|
|
|
`${env.STORAGE_URL}/files-check?token=${env.STORAGE_TOKEN}`,
|
|
|
|
|
{
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify(ids),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error("File fetch failed");
|
|
|
|
|
}
|
|
|
|
|
const parse = safeRetrive.safeParse(await response.json());
|
|
|
|
|
|
|
|
|
|
if (parse.success) {
|
|
|
|
|
return parse.data;
|
|
|
|
|
}
|
|
|
|
|
throw new Error("File fetch parse failed");
|
2025-08-28 18:27:07 +02:00
|
|
|
} catch (e) {
|
2025-10-24 16:10:59 +02:00
|
|
|
throw new Error(`File fetch failed: ${(e as Error).message}`);
|
2025-08-28 18:27:07 +02:00
|
|
|
}
|
2025-10-24 16:10:59 +02:00
|
|
|
}
|