infoalloggi-monorepo/apps/infoalloggi/src/server/services/storage.service.ts

211 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-10-24 16:10:59 +02:00
import z from "zod";
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(
`${env.STORAGE_URL}/files?token=${env.STORAGE_TOKEN}`,
);
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;
console.log("File edited successfully.");
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)) {
console.log(`File ${fileID} deleted successfully.`);
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
}