Compare commits

..

1 Commits

Author SHA1 Message Date
Nicolas Meienberger
043f73ea87 fix: properly decode path to support all special unicode characters 2025-11-21 18:25:27 +01:00
2 changed files with 7 additions and 33 deletions

View File

@@ -67,6 +67,9 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
volumeId: int("volume_id")
.notNull()
.references(() => volumesTable.id, { onDelete: "cascade" }),
repositoryId: text("repository_id")
.notNull()
.references(() => repositoriesTable.id, { onDelete: "cascade" }),
enabled: int("enabled", { mode: "boolean" }).notNull().default(true),
cronExpression: text("cron_expression").notNull(),
retentionPolicy: text("retention_policy", { mode: "json" }).$type<{
@@ -87,43 +90,14 @@ export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
createdAt: int("created_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
updatedAt: int("updated_at", { mode: "number" }).notNull().default(sql`(unixepoch())`),
});
/**
* Junction Table: Backup Schedules <-> Repositories (Many-to-Many)
*/
export const backupScheduleRepositoriesTable = sqliteTable(
"backup_schedule_repositories_table",
{
scheduleId: int("schedule_id")
.notNull()
.references(() => backupSchedulesTable.id, { onDelete: "cascade" }),
repositoryId: text("repository_id")
.notNull()
.references(() => repositoriesTable.id, { onDelete: "cascade" }),
},
(table) => ({
pk: { name: "pk_schedule_repository", columns: [table.scheduleId, table.repositoryId] },
}),
);
export const backupScheduleRelations = relations(backupSchedulesTable, ({ one, many }) => ({
export const backupScheduleRelations = relations(backupSchedulesTable, ({ one }) => ({
volume: one(volumesTable, {
fields: [backupSchedulesTable.volumeId],
references: [volumesTable.id],
}),
repositories: many(backupScheduleRepositoriesTable),
}));
export const backupScheduleRepositoryRelations = relations(backupScheduleRepositoriesTable, ({ one }) => ({
schedule: one(backupSchedulesTable, {
fields: [backupScheduleRepositoriesTable.scheduleId],
references: [backupSchedulesTable.id],
}),
repository: one(repositoriesTable, {
fields: [backupScheduleRepositoriesTable.repositoryId],
fields: [backupSchedulesTable.repositoryId],
references: [repositoriesTable.id],
}),
}));
export type BackupSchedule = typeof backupSchedulesTable.$inferSelect;
export type BackupScheduleRepository = typeof backupScheduleRepositoriesTable.$inferSelect;

View File

@@ -565,7 +565,7 @@ const ls = async (config: RepositoryConfig, snapshotId: string, path?: string) =
addRepoSpecificArgs(args, config, env);
const res = await $`restic ${args}`.env(env).nothrow().quiet();
const res = await safeSpawn({ command: "restic", args, env });
await cleanupTemporaryKeys(config, env);
if (res.exitCode !== 0) {
@@ -574,7 +574,7 @@ const ls = async (config: RepositoryConfig, snapshotId: string, path?: string) =
}
// The output is a stream of JSON objects, first is snapshot info, rest are file/dir nodes
const stdout = res.text();
const stdout = res.stdout;
const lines = stdout
.trim()
.split("\n")