refactor: convert all findMany to new structure
This commit is contained in:
parent
74714f8e74
commit
1e04c763f0
27 changed files with 304 additions and 269 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { hashPassword } from "better-auth/crypto";
|
import { hashPassword } from "better-auth/crypto";
|
||||||
import { and, eq, ne } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "~/server/db/db";
|
import { db } from "~/server/db/db";
|
||||||
import { account, usersTable, member, organization } from "~/server/db/schema";
|
import { account, usersTable, member, organization } from "~/server/db/schema";
|
||||||
import type { AuthMiddlewareContext } from "../auth";
|
import type { AuthMiddlewareContext } from "../auth";
|
||||||
|
|
@ -14,7 +14,9 @@ export const convertLegacyUserOnFirstLogin = async (ctx: AuthMiddlewareContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
const legacyUser = await db.query.usersTable.findFirst({
|
const legacyUser = await db.query.usersTable.findFirst({
|
||||||
where: and(eq(usersTable.username, body.username.trim().toLowerCase()), ne(usersTable.passwordHash, "")),
|
where: {
|
||||||
|
AND: [{ username: body.username.trim().toLowerCase() }, { passwordHash: { NOT: "" } }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (legacyUser) {
|
if (legacyUser) {
|
||||||
|
|
@ -26,7 +28,7 @@ export const convertLegacyUserOnFirstLogin = async (ctx: AuthMiddlewareContext)
|
||||||
const accountId = crypto.randomUUID();
|
const accountId = crypto.randomUUID();
|
||||||
|
|
||||||
const oldMembership = await tx.query.member.findFirst({
|
const oldMembership = await tx.query.member.findFirst({
|
||||||
where: eq(member.userId, legacyUser.id),
|
where: { userId: legacyUser.id },
|
||||||
with: {
|
with: {
|
||||||
organization: true,
|
organization: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { db } from "~/server/db/db";
|
import { db } from "~/server/db/db";
|
||||||
import type { AuthMiddlewareContext } from "../auth";
|
import type { AuthMiddlewareContext } from "../auth";
|
||||||
import { logger } from "~/server/utils/logger";
|
import { logger } from "~/server/utils/logger";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { appMetadataTable } from "~/server/db/schema";
|
|
||||||
import { ForbiddenError } from "http-errors-enhanced";
|
import { ForbiddenError } from "http-errors-enhanced";
|
||||||
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
||||||
|
|
||||||
|
|
@ -15,7 +13,7 @@ export const ensureOnlyOneUser = async (ctx: AuthMiddlewareContext) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await db.query.appMetadataTable.findFirst({
|
const result = await db.query.appMetadataTable.findFirst({
|
||||||
where: eq(appMetadataTable.key, REGISTRATION_ENABLED_KEY),
|
where: { key: REGISTRATION_ENABLED_KEY },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result?.value !== "true" && existingUser) {
|
if (result?.value !== "true" && existingUser) {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ const createBetterAuth = (secret: string) => {
|
||||||
create: {
|
create: {
|
||||||
before: async (session) => {
|
before: async (session) => {
|
||||||
const orgMembership = await db.query.member.findFirst({
|
const orgMembership = await db.query.member.findFirst({
|
||||||
where: eq(member.userId, session.userId),
|
where: { userId: session.userId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!orgMembership) {
|
if (!orgMembership) {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const listOrganizations = () => {
|
||||||
|
|
||||||
const getUserCurrentOrganization = async (userId: string) => {
|
const getUserCurrentOrganization = async (userId: string) => {
|
||||||
const membership = await db.query.member.findFirst({
|
const membership = await db.query.member.findFirst({
|
||||||
where: eq(member.userId, userId),
|
where: { userId },
|
||||||
with: {
|
with: {
|
||||||
organization: true,
|
organization: true,
|
||||||
},
|
},
|
||||||
|
|
@ -36,9 +36,7 @@ const assignUserToOrganization = async (userId: string, organizationId: string)
|
||||||
throw new Error("Organization not found");
|
throw new Error("Organization not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingMembership = await db.query.member.findFirst({
|
const existingMembership = await db.query.member.findFirst({ where: { userId } });
|
||||||
where: eq(member.userId, userId),
|
|
||||||
});
|
|
||||||
|
|
||||||
await db.transaction(async (tx) => {
|
await db.transaction(async (tx) => {
|
||||||
if (existingMembership) {
|
if (existingMembership) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Database } from "bun:sqlite";
|
import { Database } from "bun:sqlite";
|
||||||
|
import { relations } from "./relations";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { drizzle } from "drizzle-orm/bun-sqlite";
|
import { drizzle } from "drizzle-orm/bun-sqlite";
|
||||||
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
|
import { migrate } from "drizzle-orm/bun-sqlite/migrator";
|
||||||
|
|
@ -13,7 +14,7 @@ import type * as schemaTypes from "./schema";
|
||||||
* to isolate the db initialization code from the rest of the server code.
|
* to isolate the db initialization code from the rest of the server code.
|
||||||
*/
|
*/
|
||||||
let _sqlite: Database | undefined;
|
let _sqlite: Database | undefined;
|
||||||
let _db: ReturnType<typeof drizzle<typeof schemaTypes>> | undefined;
|
let _db: ReturnType<typeof initDb> | undefined;
|
||||||
let _schema: typeof schemaTypes | undefined;
|
let _schema: typeof schemaTypes | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,7 +36,7 @@ const initDb = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
_sqlite = new Database(DATABASE_URL);
|
_sqlite = new Database(DATABASE_URL);
|
||||||
return drizzle({ client: _sqlite, schema: _schema });
|
return drizzle({ client: _sqlite, relations, schema: _schema });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,7 +52,7 @@ export const db = new Proxy(
|
||||||
return Reflect.get(_db, prop, receiver);
|
return Reflect.get(_db, prop, receiver);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
) as ReturnType<typeof drizzle<typeof schemaTypes>>;
|
) as ReturnType<typeof initDb>;
|
||||||
|
|
||||||
export const runDbMigrations = () => {
|
export const runDbMigrations = () => {
|
||||||
let migrationsFolder: string;
|
let migrationsFolder: string;
|
||||||
|
|
|
||||||
141
app/server/db/relations.ts
Normal file
141
app/server/db/relations.ts
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
import { defineRelations } from "drizzle-orm";
|
||||||
|
import * as schema from "./schema";
|
||||||
|
|
||||||
|
export const relations = defineRelations(schema, (r) => ({
|
||||||
|
repositoriesTable: {
|
||||||
|
backupSchedulesTablesViaBackupScheduleMirrorsTable: r.many.backupSchedulesTable({
|
||||||
|
from: r.repositoriesTable.id.through(r.backupScheduleMirrorsTable.repositoryId),
|
||||||
|
to: r.backupSchedulesTable.id.through(r.backupScheduleMirrorsTable.scheduleId),
|
||||||
|
alias: "repositoriesTable_id_backupSchedulesTable_id_via_backupScheduleMirrorsTable",
|
||||||
|
}),
|
||||||
|
backupSchedules: r.many.backupSchedulesTable({
|
||||||
|
alias: "backupSchedulesTable_repositoryId_repositoriesTable_id",
|
||||||
|
}),
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.repositoriesTable.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
backupScheduleMirrorsTable: {
|
||||||
|
repository: r.one.repositoriesTable({
|
||||||
|
from: r.backupScheduleMirrorsTable.repositoryId,
|
||||||
|
to: r.repositoriesTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
backupSchedule: r.one.backupSchedulesTable({
|
||||||
|
from: r.backupScheduleMirrorsTable.scheduleId,
|
||||||
|
to: r.backupSchedulesTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
backupSchedulesTable: {
|
||||||
|
mirrors: r.many.repositoriesTable({
|
||||||
|
alias: "repositoriesTable_id_backupSchedulesTable_id_via_backupScheduleMirrorsTable",
|
||||||
|
}),
|
||||||
|
notificationDestinationsTables: r.many.notificationDestinationsTable(),
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.backupSchedulesTable.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
repository: r.one.repositoriesTable({
|
||||||
|
from: r.backupSchedulesTable.repositoryId,
|
||||||
|
to: r.repositoriesTable.id,
|
||||||
|
alias: "backupSchedulesTable_repositoryId_repositoriesTable_id",
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
volume: r.one.volumesTable({
|
||||||
|
from: r.backupSchedulesTable.volumeId,
|
||||||
|
to: r.volumesTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
notificationDestinationsTable: {
|
||||||
|
backupSchedules: r.many.backupSchedulesTable({
|
||||||
|
from: r.notificationDestinationsTable.id.through(r.backupScheduleNotificationsTable.destinationId),
|
||||||
|
to: r.backupSchedulesTable.id.through(r.backupScheduleNotificationsTable.scheduleId),
|
||||||
|
}),
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.notificationDestinationsTable.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
account: {
|
||||||
|
user: r.one.usersTable({
|
||||||
|
from: r.account.userId,
|
||||||
|
to: r.usersTable.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
usersTable: {
|
||||||
|
accounts: r.many.account(),
|
||||||
|
sessions: r.many.sessionsTable(),
|
||||||
|
members: r.many.member(),
|
||||||
|
twoFactors: r.many.twoFactor(),
|
||||||
|
organizations: r.many.organization({
|
||||||
|
from: r.usersTable.id.through(r.member.userId),
|
||||||
|
to: r.organization.id.through(r.member.organizationId),
|
||||||
|
alias: "usersTable_id_organization_id_via_member",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
sessionsTable: {
|
||||||
|
user: r.one.usersTable({
|
||||||
|
from: r.sessionsTable.userId,
|
||||||
|
to: r.usersTable.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
twoFactor: {
|
||||||
|
usersTable: r.one.usersTable({
|
||||||
|
from: r.twoFactor.userId,
|
||||||
|
to: r.usersTable.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
organization: {
|
||||||
|
users: r.many.usersTable({
|
||||||
|
alias: "usersTable_id_organization_id_via_member",
|
||||||
|
}),
|
||||||
|
backupSchedules: r.many.backupSchedulesTable(),
|
||||||
|
notificationDestinations: r.many.notificationDestinationsTable(),
|
||||||
|
repositories: r.many.repositoriesTable(),
|
||||||
|
volumes: r.many.volumesTable(),
|
||||||
|
members: r.many.member(),
|
||||||
|
invitations: r.many.invitation(),
|
||||||
|
},
|
||||||
|
volumesTable: {
|
||||||
|
backupSchedules: r.many.backupSchedulesTable(),
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.volumesTable.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
member: {
|
||||||
|
user: r.one.usersTable({
|
||||||
|
from: r.member.userId,
|
||||||
|
to: r.usersTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.member.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
invitation: {
|
||||||
|
organization: r.one.organization({
|
||||||
|
from: r.invitation.organizationId,
|
||||||
|
to: r.organization.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
backupScheduleNotificationsTable: {
|
||||||
|
destination: r.one.notificationDestinationsTable({
|
||||||
|
from: r.backupScheduleNotificationsTable.destinationId,
|
||||||
|
to: r.notificationDestinationsTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
backupSchedule: r.one.backupSchedulesTable({
|
||||||
|
from: r.backupScheduleNotificationsTable.scheduleId,
|
||||||
|
to: r.backupSchedulesTable.id,
|
||||||
|
optional: false,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { relations, sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
import { index, int, integer, sqliteTable, text, real, primaryKey, unique, uniqueIndex } from "drizzle-orm/sqlite-core";
|
import { index, int, integer, sqliteTable, text, real, primaryKey, unique, uniqueIndex } from "drizzle-orm/sqlite-core";
|
||||||
import type {
|
import type {
|
||||||
CompressionMode,
|
CompressionMode,
|
||||||
|
|
@ -175,29 +175,33 @@ export const invitation = sqliteTable(
|
||||||
/**
|
/**
|
||||||
* Volumes Table
|
* Volumes Table
|
||||||
*/
|
*/
|
||||||
export const volumesTable = sqliteTable("volumes_table", {
|
export const volumesTable = sqliteTable(
|
||||||
id: int().primaryKey({ autoIncrement: true }),
|
"volumes_table",
|
||||||
shortId: text("short_id").notNull().unique(),
|
{
|
||||||
name: text().notNull(),
|
id: int().primaryKey({ autoIncrement: true }),
|
||||||
type: text().$type<BackendType>().notNull(),
|
shortId: text("short_id").notNull().unique(),
|
||||||
status: text().$type<BackendStatus>().notNull().default("unmounted"),
|
name: text().notNull(),
|
||||||
lastError: text("last_error"),
|
type: text().$type<BackendType>().notNull(),
|
||||||
lastHealthCheck: integer("last_health_check", { mode: "number" })
|
status: text().$type<BackendStatus>().notNull().default("unmounted"),
|
||||||
.notNull()
|
lastError: text("last_error"),
|
||||||
.default(sql`(unixepoch() * 1000)`),
|
lastHealthCheck: integer("last_health_check", { mode: "number" })
|
||||||
createdAt: integer("created_at", { mode: "number" })
|
.notNull()
|
||||||
.notNull()
|
.default(sql`(unixepoch() * 1000)`),
|
||||||
.default(sql`(unixepoch() * 1000)`),
|
createdAt: integer("created_at", { mode: "number" })
|
||||||
updatedAt: integer("updated_at", { mode: "number" })
|
.notNull()
|
||||||
.notNull()
|
.default(sql`(unixepoch() * 1000)`),
|
||||||
.$onUpdate(() => Date.now())
|
updatedAt: integer("updated_at", { mode: "number" })
|
||||||
.default(sql`(unixepoch() * 1000)`),
|
.notNull()
|
||||||
config: text("config", { mode: "json" }).$type<typeof volumeConfigSchema.inferOut>().notNull(),
|
.$onUpdate(() => Date.now())
|
||||||
autoRemount: int("auto_remount", { mode: "boolean" }).notNull().default(true),
|
.default(sql`(unixepoch() * 1000)`),
|
||||||
organizationId: text("organization_id")
|
config: text("config", { mode: "json" }).$type<typeof volumeConfigSchema.inferOut>().notNull(),
|
||||||
.notNull()
|
autoRemount: int("auto_remount", { mode: "boolean" }).notNull().default(true),
|
||||||
.references(() => organization.id, { onDelete: "cascade" }),
|
organizationId: text("organization_id")
|
||||||
}, (table) => [unique().on(table.name, table.organizationId)]);
|
.notNull()
|
||||||
|
.references(() => organization.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(table) => [unique().on(table.name, table.organizationId)],
|
||||||
|
);
|
||||||
export type Volume = typeof volumesTable.$inferSelect;
|
export type Volume = typeof volumesTable.$inferSelect;
|
||||||
export type VolumeInsert = typeof volumesTable.$inferInsert;
|
export type VolumeInsert = typeof volumesTable.$inferInsert;
|
||||||
|
|
||||||
|
|
@ -381,102 +385,3 @@ export const twoFactor = sqliteTable(
|
||||||
},
|
},
|
||||||
(table) => [index("twoFactor_secret_idx").on(table.secret), index("twoFactor_userId_idx").on(table.userId)],
|
(table) => [index("twoFactor_secret_idx").on(table.secret), index("twoFactor_userId_idx").on(table.userId)],
|
||||||
);
|
);
|
||||||
|
|
||||||
export const userRelations = relations(usersTable, ({ many }) => ({
|
|
||||||
sessions: many(sessionsTable),
|
|
||||||
accounts: many(account),
|
|
||||||
members: many(member),
|
|
||||||
invitations: many(invitation),
|
|
||||||
twoFactors: many(twoFactor),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const sessionRelations = relations(sessionsTable, ({ one }) => ({
|
|
||||||
user: one(usersTable, {
|
|
||||||
fields: [sessionsTable.userId],
|
|
||||||
references: [usersTable.id],
|
|
||||||
}),
|
|
||||||
activeOrganization: one(organization, {
|
|
||||||
fields: [sessionsTable.activeOrganizationId],
|
|
||||||
references: [organization.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const accountRelations = relations(account, ({ one }) => ({
|
|
||||||
user: one(usersTable, {
|
|
||||||
fields: [account.userId],
|
|
||||||
references: [usersTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const organizationRelations = relations(organization, ({ many }) => ({
|
|
||||||
members: many(member),
|
|
||||||
invitations: many(invitation),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const memberRelations = relations(member, ({ one }) => ({
|
|
||||||
organization: one(organization, {
|
|
||||||
fields: [member.organizationId],
|
|
||||||
references: [organization.id],
|
|
||||||
}),
|
|
||||||
usersTable: one(usersTable, {
|
|
||||||
fields: [member.userId],
|
|
||||||
references: [usersTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const invitationRelations = relations(invitation, ({ one }) => ({
|
|
||||||
organization: one(organization, {
|
|
||||||
fields: [invitation.organizationId],
|
|
||||||
references: [organization.id],
|
|
||||||
}),
|
|
||||||
usersTable: one(usersTable, {
|
|
||||||
fields: [invitation.inviterId],
|
|
||||||
references: [usersTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const twoFactorRelations = relations(twoFactor, ({ one }) => ({
|
|
||||||
usersTable: one(usersTable, {
|
|
||||||
fields: [twoFactor.userId],
|
|
||||||
references: [usersTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const backupScheduleMirrorRelations = relations(backupScheduleMirrorsTable, ({ one }) => ({
|
|
||||||
schedule: one(backupSchedulesTable, {
|
|
||||||
fields: [backupScheduleMirrorsTable.scheduleId],
|
|
||||||
references: [backupSchedulesTable.id],
|
|
||||||
}),
|
|
||||||
repository: one(repositoriesTable, {
|
|
||||||
fields: [backupScheduleMirrorsTable.repositoryId],
|
|
||||||
references: [repositoriesTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const backupScheduleRelations = relations(backupSchedulesTable, ({ one, many }) => ({
|
|
||||||
volume: one(volumesTable, {
|
|
||||||
fields: [backupSchedulesTable.volumeId],
|
|
||||||
references: [volumesTable.id],
|
|
||||||
}),
|
|
||||||
repository: one(repositoriesTable, {
|
|
||||||
fields: [backupSchedulesTable.repositoryId],
|
|
||||||
references: [repositoriesTable.id],
|
|
||||||
}),
|
|
||||||
notifications: many(backupScheduleNotificationsTable),
|
|
||||||
mirrors: many(backupScheduleMirrorsTable),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const notificationDestinationRelations = relations(notificationDestinationsTable, ({ many }) => ({
|
|
||||||
schedules: many(backupScheduleNotificationsTable),
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const backupScheduleNotificationRelations = relations(backupScheduleNotificationsTable, ({ one }) => ({
|
|
||||||
schedule: one(backupSchedulesTable, {
|
|
||||||
fields: [backupScheduleNotificationsTable.scheduleId],
|
|
||||||
references: [backupSchedulesTable.id],
|
|
||||||
}),
|
|
||||||
destination: one(notificationDestinationsTable, {
|
|
||||||
fields: [backupScheduleNotificationsTable.destinationId],
|
|
||||||
references: [notificationDestinationsTable.id],
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ import { Job } from "../core/scheduler";
|
||||||
import { volumeService } from "../modules/volumes/volume.service";
|
import { volumeService } from "../modules/volumes/volume.service";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { db } from "../db/db";
|
import { db } from "../db/db";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { volumesTable } from "../db/schema";
|
|
||||||
import { withContext } from "../core/request-context";
|
import { withContext } from "../core/request-context";
|
||||||
|
|
||||||
export class VolumeAutoRemountJob extends Job {
|
export class VolumeAutoRemountJob extends Job {
|
||||||
|
|
@ -11,7 +9,7 @@ export class VolumeAutoRemountJob extends Job {
|
||||||
logger.debug("Running auto-remount for all errored volumes...");
|
logger.debug("Running auto-remount for all errored volumes...");
|
||||||
|
|
||||||
const volumes = await db.query.volumesTable.findMany({
|
const volumes = await db.query.volumesTable.findMany({
|
||||||
where: eq(volumesTable.status, "error"),
|
where: { status: "error" },
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const volume of volumes) {
|
for (const volume of volumes) {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ import { Job } from "../core/scheduler";
|
||||||
import { volumeService } from "../modules/volumes/volume.service";
|
import { volumeService } from "../modules/volumes/volume.service";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { db } from "../db/db";
|
import { db } from "../db/db";
|
||||||
import { eq, or } from "drizzle-orm";
|
|
||||||
import { volumesTable } from "../db/schema";
|
|
||||||
import { withContext } from "../core/request-context";
|
import { withContext } from "../core/request-context";
|
||||||
|
|
||||||
export class VolumeHealthCheckJob extends Job {
|
export class VolumeHealthCheckJob extends Job {
|
||||||
|
|
@ -11,7 +9,9 @@ export class VolumeHealthCheckJob extends Job {
|
||||||
logger.debug("Running health check for all volumes...");
|
logger.debug("Running health check for all volumes...");
|
||||||
|
|
||||||
const volumes = await db.query.volumesTable.findMany({
|
const volumes = await db.query.volumesTable.findMany({
|
||||||
where: or(eq(volumesTable.status, "mounted"), eq(volumesTable.status, "error")),
|
where: {
|
||||||
|
OR: [{ status: "mounted" }, { status: "error" }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const volume of volumes) {
|
for (const volume of volumes) {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ import { Job } from "../core/scheduler";
|
||||||
import { repositoriesService } from "../modules/repositories/repositories.service";
|
import { repositoriesService } from "../modules/repositories/repositories.service";
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import { db } from "../db/db";
|
import { db } from "../db/db";
|
||||||
import { eq, or } from "drizzle-orm";
|
|
||||||
import { repositoriesTable } from "../db/schema";
|
|
||||||
import { withContext } from "../core/request-context";
|
import { withContext } from "../core/request-context";
|
||||||
|
|
||||||
export class RepositoryHealthCheckJob extends Job {
|
export class RepositoryHealthCheckJob extends Job {
|
||||||
|
|
@ -11,7 +9,7 @@ export class RepositoryHealthCheckJob extends Job {
|
||||||
logger.debug("Running health check for all repositories...");
|
logger.debug("Running health check for all repositories...");
|
||||||
|
|
||||||
const repositories = await db.query.repositoriesTable.findMany({
|
const repositories = await db.query.repositoriesTable.findMany({
|
||||||
where: or(eq(repositoriesTable.status, "healthy"), eq(repositoriesTable.status, "error")),
|
where: { OR: [{ status: "healthy" }, { status: "error" }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const repository of repositories) {
|
for (const repository of repositories) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import { createMiddleware } from "hono/factory";
|
import { createMiddleware } from "hono/factory";
|
||||||
import { auth } from "~/lib/auth";
|
import { auth } from "~/lib/auth";
|
||||||
import { db } from "~/server/db/db";
|
import { db } from "~/server/db/db";
|
||||||
import { member } from "~/server/db/schema";
|
|
||||||
import { eq, and } from "drizzle-orm";
|
|
||||||
import { withContext } from "~/server/core/request-context";
|
import { withContext } from "~/server/core/request-context";
|
||||||
|
|
||||||
declare module "hono" {
|
declare module "hono" {
|
||||||
|
|
@ -34,7 +32,9 @@ export const requireAuth = createMiddleware(async (c, next) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const membership = await db.query.member.findFirst({
|
const membership = await db.query.member.findFirst({
|
||||||
where: and(eq(member.userId, user.id), eq(member.organizationId, activeOrganizationId)),
|
where: {
|
||||||
|
AND: [{ userId: user.id }, { organizationId: activeOrganizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!membership) {
|
if (!membership) {
|
||||||
|
|
@ -58,7 +58,9 @@ export const requireOrgAdmin = createMiddleware(async (c, next) => {
|
||||||
const organizationId = c.get("organizationId");
|
const organizationId = c.get("organizationId");
|
||||||
|
|
||||||
const membership = await db.query.member.findFirst({
|
const membership = await db.query.member.findFirst({
|
||||||
where: and(eq(member.userId, user.id), eq(member.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ userId: user.id }, { organizationId: organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!membership || (membership.role !== "owner" && membership.role !== "admin")) {
|
if (!membership || (membership.role !== "owner" && membership.role !== "admin")) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ export class AuthService {
|
||||||
*/
|
*/
|
||||||
async getUserDeletionImpact(userId: string): Promise<UserDeletionImpactDto> {
|
async getUserDeletionImpact(userId: string): Promise<UserDeletionImpactDto> {
|
||||||
const userMemberships = await db.query.member.findMany({
|
const userMemberships = await db.query.member.findMany({
|
||||||
where: and(eq(member.userId, userId), eq(member.role, "owner")),
|
where: {
|
||||||
|
AND: [{ userId: userId }, { role: "owner" }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const impacts: UserDeletionImpactDto["organizations"] = [];
|
const impacts: UserDeletionImpactDto["organizations"] = [];
|
||||||
|
|
@ -43,7 +45,7 @@ export class AuthService {
|
||||||
|
|
||||||
if (otherOwners[0].count === 0) {
|
if (otherOwners[0].count === 0) {
|
||||||
const org = await db.query.organization.findFirst({
|
const org = await db.query.organization.findFirst({
|
||||||
where: eq(organization.id, membership.organizationId),
|
where: { id: membership.organizationId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (org) {
|
if (org) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { verifyPassword } from "better-auth/crypto";
|
import { verifyPassword } from "better-auth/crypto";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { db } from "~/server/db/db";
|
import { db } from "~/server/db/db";
|
||||||
import { account } from "~/server/db/schema";
|
|
||||||
|
|
||||||
type PasswordVerificationBody = {
|
type PasswordVerificationBody = {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
|
@ -10,7 +8,7 @@ type PasswordVerificationBody = {
|
||||||
|
|
||||||
export const verifyUserPassword = async ({ password, userId }: PasswordVerificationBody) => {
|
export const verifyUserPassword = async ({ password, userId }: PasswordVerificationBody) => {
|
||||||
const userAccount = await db.query.account.findFirst({
|
const userAccount = await db.query.account.findFirst({
|
||||||
where: eq(account.userId, userId),
|
where: { userId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!userAccount || !userAccount.password) {
|
if (!userAccount || !userAccount.password) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { and, asc, eq, isNull, ne, or } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import cron from "node-cron";
|
import cron from "node-cron";
|
||||||
import { CronExpressionParser } from "cron-parser";
|
import { CronExpressionParser } from "cron-parser";
|
||||||
import { NotFoundError, BadRequestError, ConflictError } from "http-errors-enhanced";
|
import { NotFoundError, BadRequestError, ConflictError } from "http-errors-enhanced";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { backupSchedulesTable, backupScheduleMirrorsTable, repositoriesTable, volumesTable } from "../../db/schema";
|
import { backupSchedulesTable, backupScheduleMirrorsTable, repositoriesTable } from "../../db/schema";
|
||||||
import { restic } from "../../utils/restic";
|
import { restic } from "../../utils/restic";
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { cache } from "../../utils/cache";
|
import { cache } from "../../utils/cache";
|
||||||
|
|
@ -60,12 +60,9 @@ const processPattern = (pattern: string, volumePath: string) => {
|
||||||
const listSchedules = async () => {
|
const listSchedules = async () => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedules = await db.query.backupSchedulesTable.findMany({
|
const schedules = await db.query.backupSchedulesTable.findMany({
|
||||||
where: eq(backupSchedulesTable.organizationId, organizationId),
|
where: { organizationId },
|
||||||
with: {
|
with: { volume: true, repository: true },
|
||||||
volume: true,
|
orderBy: { sortOrder: "asc", id: "asc" },
|
||||||
repository: true,
|
|
||||||
},
|
|
||||||
orderBy: [asc(backupSchedulesTable.sortOrder), asc(backupSchedulesTable.id)],
|
|
||||||
});
|
});
|
||||||
return schedules;
|
return schedules;
|
||||||
};
|
};
|
||||||
|
|
@ -73,11 +70,8 @@ const listSchedules = async () => {
|
||||||
const getSchedule = async (scheduleId: number) => {
|
const getSchedule = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
with: {
|
with: { volume: true, repository: true },
|
||||||
volume: true,
|
|
||||||
repository: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -94,7 +88,9 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingName = await db.query.backupSchedulesTable.findFirst({
|
const existingName = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.name, data.name), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ name: data.name }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingName) {
|
if (existingName) {
|
||||||
|
|
@ -102,7 +98,9 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const volume = await db.query.volumesTable.findFirst({
|
const volume = await db.query.volumesTable.findFirst({
|
||||||
where: and(eq(volumesTable.id, data.volumeId), eq(volumesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: data.volumeId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!volume) {
|
if (!volume) {
|
||||||
|
|
@ -110,7 +108,9 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const repository = await db.query.repositoriesTable.findFirst({
|
const repository = await db.query.repositoriesTable.findFirst({
|
||||||
where: and(eq(repositoriesTable.id, data.repositoryId), eq(repositoriesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: data.repositoryId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
|
|
@ -148,7 +148,9 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
|
||||||
const updateSchedule = async (scheduleId: number, data: UpdateBackupScheduleBody) => {
|
const updateSchedule = async (scheduleId: number, data: UpdateBackupScheduleBody) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: scheduleId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -161,11 +163,9 @@ const updateSchedule = async (scheduleId: number, data: UpdateBackupScheduleBody
|
||||||
|
|
||||||
if (data.name) {
|
if (data.name) {
|
||||||
const existingName = await db.query.backupSchedulesTable.findFirst({
|
const existingName = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(
|
where: {
|
||||||
eq(backupSchedulesTable.name, data.name),
|
AND: [{ name: data.name }, { NOT: { id: scheduleId } }, { organizationId }],
|
||||||
ne(backupSchedulesTable.id, scheduleId),
|
},
|
||||||
eq(backupSchedulesTable.organizationId, organizationId),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingName) {
|
if (existingName) {
|
||||||
|
|
@ -174,7 +174,9 @@ const updateSchedule = async (scheduleId: number, data: UpdateBackupScheduleBody
|
||||||
}
|
}
|
||||||
|
|
||||||
const repository = await db.query.repositoriesTable.findFirst({
|
const repository = await db.query.repositoriesTable.findFirst({
|
||||||
where: and(eq(repositoriesTable.id, data.repositoryId), eq(repositoriesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: data.repositoryId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
|
|
@ -200,7 +202,9 @@ const updateSchedule = async (scheduleId: number, data: UpdateBackupScheduleBody
|
||||||
const deleteSchedule = async (scheduleId: number) => {
|
const deleteSchedule = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: scheduleId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -215,7 +219,7 @@ const deleteSchedule = async (scheduleId: number) => {
|
||||||
const executeBackup = async (scheduleId: number, manual = false) => {
|
const executeBackup = async (scheduleId: number, manual = false) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -233,7 +237,7 @@ const executeBackup = async (scheduleId: number, manual = false) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const volume = await db.query.volumesTable.findFirst({
|
const volume = await db.query.volumesTable.findFirst({
|
||||||
where: and(eq(volumesTable.id, schedule.volumeId), eq(volumesTable.organizationId, organizationId)),
|
where: { AND: [{ id: schedule.volumeId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!volume) {
|
if (!volume) {
|
||||||
|
|
@ -241,7 +245,7 @@ const executeBackup = async (scheduleId: number, manual = false) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const repository = await db.query.repositoriesTable.findFirst({
|
const repository = await db.query.repositoriesTable.findFirst({
|
||||||
where: and(eq(repositoriesTable.id, schedule.repositoryId), eq(repositoriesTable.organizationId, organizationId)),
|
where: { AND: [{ id: schedule.repositoryId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
|
|
@ -436,11 +440,9 @@ const getSchedulesToExecute = async () => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const schedules = await db.query.backupSchedulesTable.findMany({
|
const schedules = await db.query.backupSchedulesTable.findMany({
|
||||||
where: and(
|
where: {
|
||||||
eq(backupSchedulesTable.enabled, true),
|
AND: [{ enabled: true }, { lastBackupStatus: { NOT: "in_progress" } }, { organizationId }],
|
||||||
or(ne(backupSchedulesTable.lastBackupStatus, "in_progress"), isNull(backupSchedulesTable.lastBackupStatus)),
|
},
|
||||||
eq(backupSchedulesTable.organizationId, organizationId),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const schedulesToRun: number[] = [];
|
const schedulesToRun: number[] = [];
|
||||||
|
|
@ -457,7 +459,7 @@ const getSchedulesToExecute = async () => {
|
||||||
const getScheduleForVolume = async (volumeId: number) => {
|
const getScheduleForVolume = async (volumeId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.volumeId, volumeId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ volumeId }, { organizationId }] },
|
||||||
with: { volume: true, repository: true },
|
with: { volume: true, repository: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -467,7 +469,7 @@ const getScheduleForVolume = async (volumeId: number) => {
|
||||||
const stopBackup = async (scheduleId: number) => {
|
const stopBackup = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -498,7 +500,9 @@ const stopBackup = async (scheduleId: number) => {
|
||||||
const runForget = async (scheduleId: number, repositoryId?: string) => {
|
const runForget = async (scheduleId: number, repositoryId?: string) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: scheduleId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -510,10 +514,9 @@ const runForget = async (scheduleId: number, repositoryId?: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const repository = await db.query.repositoriesTable.findFirst({
|
const repository = await db.query.repositoriesTable.findFirst({
|
||||||
where: and(
|
where: {
|
||||||
eq(repositoriesTable.id, repositoryId ?? schedule.repositoryId),
|
AND: [{ id: repositoryId ?? schedule.repositoryId }, { organizationId }],
|
||||||
eq(repositoriesTable.organizationId, organizationId),
|
},
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
|
|
@ -535,7 +538,9 @@ const runForget = async (scheduleId: number, repositoryId?: string) => {
|
||||||
const getMirrors = async (scheduleId: number) => {
|
const getMirrors = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: {
|
||||||
|
AND: [{ id: scheduleId }, { organizationId }],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -543,7 +548,9 @@ const getMirrors = async (scheduleId: number) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
const mirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
||||||
where: eq(backupScheduleMirrorsTable.scheduleId, scheduleId),
|
where: {
|
||||||
|
scheduleId,
|
||||||
|
},
|
||||||
with: { repository: true },
|
with: { repository: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -553,7 +560,7 @@ const getMirrors = async (scheduleId: number) => {
|
||||||
const updateMirrors = async (scheduleId: number, data: UpdateScheduleMirrorsBody) => {
|
const updateMirrors = async (scheduleId: number, data: UpdateScheduleMirrorsBody) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
with: { repository: true },
|
with: { repository: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -567,7 +574,7 @@ const updateMirrors = async (scheduleId: number, data: UpdateScheduleMirrorsBody
|
||||||
}
|
}
|
||||||
|
|
||||||
const repo = await db.query.repositoriesTable.findFirst({
|
const repo = await db.query.repositoriesTable.findFirst({
|
||||||
where: and(eq(repositoriesTable.id, mirror.repositoryId), eq(repositoriesTable.organizationId, organizationId)),
|
where: { AND: [{ id: mirror.repositoryId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repo) {
|
if (!repo) {
|
||||||
|
|
@ -584,7 +591,7 @@ const updateMirrors = async (scheduleId: number, data: UpdateScheduleMirrorsBody
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingMirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
const existingMirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
||||||
where: eq(backupScheduleMirrorsTable.scheduleId, scheduleId),
|
where: { scheduleId },
|
||||||
});
|
});
|
||||||
|
|
||||||
const existingMirrorsMap = new Map(
|
const existingMirrorsMap = new Map(
|
||||||
|
|
@ -622,7 +629,7 @@ const copyToMirrors = async (
|
||||||
) => {
|
) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -630,7 +637,7 @@ const copyToMirrors = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
const mirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
const mirrors = await db.query.backupScheduleMirrorsTable.findMany({
|
||||||
where: eq(backupScheduleMirrorsTable.scheduleId, scheduleId),
|
where: { scheduleId },
|
||||||
with: { repository: true },
|
with: { repository: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -712,7 +719,7 @@ const copyToMirrors = async (
|
||||||
const getMirrorCompatibility = async (scheduleId: number) => {
|
const getMirrorCompatibility = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
with: { repository: true },
|
with: { repository: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -720,9 +727,7 @@ const getMirrorCompatibility = async (scheduleId: number) => {
|
||||||
throw new NotFoundError("Backup schedule not found");
|
throw new NotFoundError("Backup schedule not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const allRepositories = await db.query.repositoriesTable.findMany({
|
const allRepositories = await db.query.repositoriesTable.findMany({ where: { organizationId } });
|
||||||
where: eq(repositoriesTable.organizationId, organizationId),
|
|
||||||
});
|
|
||||||
const repos = allRepositories.filter((repo) => repo.id !== schedule.repositoryId);
|
const repos = allRepositories.filter((repo) => repo.id !== schedule.repositoryId);
|
||||||
|
|
||||||
const compatibility = await Promise.all(
|
const compatibility = await Promise.all(
|
||||||
|
|
@ -740,7 +745,7 @@ const reorderSchedules = async (scheduleIds: number[]) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingSchedules = await db.query.backupSchedulesTable.findMany({
|
const existingSchedules = await db.query.backupSchedulesTable.findMany({
|
||||||
where: eq(backupSchedulesTable.organizationId, organizationId),
|
where: { organizationId },
|
||||||
columns: { id: true },
|
columns: { id: true },
|
||||||
});
|
});
|
||||||
const existingIds = new Set(existingSchedules.map((s) => s.id));
|
const existingIds = new Set(existingSchedules.map((s) => s.id));
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { v00001 } from "./migrations/00001-retag-snapshots";
|
||||||
import { v00002 } from "./migrations/00002-isolate-restic-passwords";
|
import { v00002 } from "./migrations/00002-isolate-restic-passwords";
|
||||||
import { v00003 } from "./migrations/00003-assign-organization";
|
import { v00003 } from "./migrations/00003-assign-organization";
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { appMetadataTable, usersTable } from "../../db/schema";
|
import { appMetadataTable, usersTable } from "../../db/schema";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
|
|
||||||
|
|
@ -26,9 +25,7 @@ const recordMigrationCheckpoint = async (version: string): Promise<void> => {
|
||||||
|
|
||||||
const hasMigrationCheckpoint = async (id: string): Promise<boolean> => {
|
const hasMigrationCheckpoint = async (id: string): Promise<boolean> => {
|
||||||
const key = `${MIGRATION_KEY_PREFIX}${id}`;
|
const key = `${MIGRATION_KEY_PREFIX}${id}`;
|
||||||
const result = await db.query.appMetadataTable.findFirst({
|
const result = await db.query.appMetadataTable.findFirst({ where: { key } });
|
||||||
where: eq(appMetadataTable.key, key),
|
|
||||||
});
|
|
||||||
return result !== undefined;
|
return result !== undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../../../db/db";
|
import { db } from "../../../db/db";
|
||||||
import { backupScheduleMirrorsTable, repositoriesTable, type Repository } from "../../../db/schema";
|
import { backupScheduleMirrorsTable, type Repository } from "../../../db/schema";
|
||||||
import { logger } from "../../../utils/logger";
|
import { logger } from "../../../utils/logger";
|
||||||
import { toMessage } from "~/server/utils/errors";
|
import { toMessage } from "~/server/utils/errors";
|
||||||
import { exec } from "~/server/utils/spawn";
|
import { exec } from "~/server/utils/spawn";
|
||||||
|
|
@ -42,7 +42,7 @@ const execute = async () => {
|
||||||
const newTag = schedule.shortId;
|
const newTag = schedule.shortId;
|
||||||
|
|
||||||
const repository = await db.query.repositoriesTable.findFirst({
|
const repository = await db.query.repositoriesTable.findFirst({
|
||||||
where: eq(repositoriesTable.id, schedule.repositoryId),
|
where: { id: schedule.repositoryId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!repository) {
|
if (!repository) {
|
||||||
|
|
@ -63,7 +63,7 @@ const execute = async () => {
|
||||||
|
|
||||||
for (const mirror of mirrors) {
|
for (const mirror of mirrors) {
|
||||||
const mirrorRepo = await db.query.repositoriesTable.findFirst({
|
const mirrorRepo = await db.query.repositoriesTable.findFirst({
|
||||||
where: eq(repositoriesTable.id, mirror.repositoryId),
|
where: { id: mirror.repositoryId },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!mirrorRepo) {
|
if (!mirrorRepo) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { db } from "../../../db/db";
|
import { db } from "../../../db/db";
|
||||||
import { member, usersTable } from "../../../db/schema";
|
import { member } from "../../../db/schema";
|
||||||
import { logger } from "../../../utils/logger";
|
import { logger } from "../../../utils/logger";
|
||||||
import { toMessage } from "~/server/utils/errors";
|
import { toMessage } from "~/server/utils/errors";
|
||||||
|
|
||||||
|
|
@ -8,7 +7,9 @@ const execute = async () => {
|
||||||
const errors: Array<{ name: string; error: string }> = [];
|
const errors: Array<{ name: string; error: string }> = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const allUsers = await db.query.usersTable.findMany({ where: eq(usersTable.role, "admin") });
|
const allUsers = await db.query.usersTable.findMany({
|
||||||
|
where: { role: "admin" },
|
||||||
|
});
|
||||||
const allOrganizations = await db.query.organization.findMany({});
|
const allOrganizations = await db.query.organization.findMany({});
|
||||||
|
|
||||||
if (allUsers.length === 0) {
|
if (allUsers.length === 0) {
|
||||||
|
|
@ -35,7 +36,7 @@ const execute = async () => {
|
||||||
const org = allOrganizations[0];
|
const org = allOrganizations[0];
|
||||||
|
|
||||||
const existingMembers = await db.query.member.findMany({
|
const existingMembers = await db.query.member.findMany({
|
||||||
where: (memberTable, { eq }) => eq(memberTable.userId, user.id),
|
where: { userId: user.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingMembers.length > 0) {
|
if (existingMembers.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { Scheduler } from "../../core/scheduler";
|
import { Scheduler } from "../../core/scheduler";
|
||||||
import { eq, or } from "drizzle-orm";
|
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { volumesTable } from "../../db/schema";
|
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { createVolumeBackend } from "../backends/backend";
|
import { createVolumeBackend } from "../backends/backend";
|
||||||
|
|
||||||
|
|
@ -9,7 +7,7 @@ export const shutdown = async () => {
|
||||||
await Scheduler.stop();
|
await Scheduler.stop();
|
||||||
|
|
||||||
const volumes = await db.query.volumesTable.findMany({
|
const volumes = await db.query.volumesTable.findMany({
|
||||||
where: or(eq(volumesTable.status, "mounted")),
|
where: { status: "mounted" },
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const volume of volumes) {
|
for (const volume of volumes) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Scheduler } from "../../core/scheduler";
|
import { Scheduler } from "../../core/scheduler";
|
||||||
import { and, eq, or } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { backupSchedulesTable, volumesTable } from "../../db/schema";
|
import { backupSchedulesTable } from "../../db/schema";
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { volumeService } from "../volumes/volume.service";
|
import { volumeService } from "../volumes/volume.service";
|
||||||
import { CleanupDanglingMountsJob } from "../../jobs/cleanup-dangling";
|
import { CleanupDanglingMountsJob } from "../../jobs/cleanup-dangling";
|
||||||
|
|
@ -62,10 +62,14 @@ export const startup = async () => {
|
||||||
await ensureLatestConfigurationSchema();
|
await ensureLatestConfigurationSchema();
|
||||||
|
|
||||||
const volumes = await db.query.volumesTable.findMany({
|
const volumes = await db.query.volumesTable.findMany({
|
||||||
where: or(
|
where: {
|
||||||
eq(volumesTable.status, "mounted"),
|
OR: [
|
||||||
and(eq(volumesTable.autoRemount, true), eq(volumesTable.status, "error")),
|
{ status: "mounted" },
|
||||||
),
|
{
|
||||||
|
AND: [{ autoRemount: true }, { status: "error" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const volume of volumes) {
|
for (const volume of volumes) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { eq, and, inArray } from "drizzle-orm";
|
import { eq, and } from "drizzle-orm";
|
||||||
import { BadRequestError, ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
|
import { BadRequestError, ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import {
|
import {
|
||||||
notificationDestinationsTable,
|
notificationDestinationsTable,
|
||||||
backupScheduleNotificationsTable,
|
backupScheduleNotificationsTable,
|
||||||
backupSchedulesTable,
|
|
||||||
type NotificationDestination,
|
type NotificationDestination,
|
||||||
} from "../../db/schema";
|
} from "../../db/schema";
|
||||||
import { cryptoUtils } from "../../utils/crypto";
|
import { cryptoUtils } from "../../utils/crypto";
|
||||||
|
|
@ -19,8 +18,8 @@ import { getOrganizationId } from "~/server/core/request-context";
|
||||||
const listDestinations = async () => {
|
const listDestinations = async () => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const destinations = await db.query.notificationDestinationsTable.findMany({
|
const destinations = await db.query.notificationDestinationsTable.findMany({
|
||||||
where: eq(notificationDestinationsTable.organizationId, organizationId),
|
where: { organizationId },
|
||||||
orderBy: (destinations, { asc }) => [asc(destinations.name)],
|
orderBy: { name: "asc" },
|
||||||
});
|
});
|
||||||
return destinations;
|
return destinations;
|
||||||
};
|
};
|
||||||
|
|
@ -28,10 +27,7 @@ const listDestinations = async () => {
|
||||||
const getDestination = async (id: number) => {
|
const getDestination = async (id: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const destination = await db.query.notificationDestinationsTable.findFirst({
|
const destination = await db.query.notificationDestinationsTable.findFirst({
|
||||||
where: and(
|
where: { AND: [{ id }, { organizationId }] },
|
||||||
eq(notificationDestinationsTable.id, id),
|
|
||||||
eq(notificationDestinationsTable.organizationId, organizationId),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
|
|
@ -256,7 +252,7 @@ const testDestination = async (id: number) => {
|
||||||
const getScheduleNotifications = async (scheduleId: number) => {
|
const getScheduleNotifications = async (scheduleId: number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -264,7 +260,7 @@ const getScheduleNotifications = async (scheduleId: number) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const assignments = await db.query.backupScheduleNotificationsTable.findMany({
|
const assignments = await db.query.backupScheduleNotificationsTable.findMany({
|
||||||
where: eq(backupScheduleNotificationsTable.scheduleId, scheduleId),
|
where: { scheduleId },
|
||||||
with: {
|
with: {
|
||||||
destination: true,
|
destination: true,
|
||||||
},
|
},
|
||||||
|
|
@ -285,7 +281,7 @@ const updateScheduleNotifications = async (
|
||||||
) => {
|
) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const schedule = await db.query.backupSchedulesTable.findFirst({
|
const schedule = await db.query.backupSchedulesTable.findFirst({
|
||||||
where: and(eq(backupSchedulesTable.id, scheduleId), eq(backupSchedulesTable.organizationId, organizationId)),
|
where: { AND: [{ id: scheduleId }, { organizationId }] },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!schedule) {
|
if (!schedule) {
|
||||||
|
|
@ -295,10 +291,9 @@ const updateScheduleNotifications = async (
|
||||||
const destinationIds = [...new Set(assignments.map((a) => a.destinationId))];
|
const destinationIds = [...new Set(assignments.map((a) => a.destinationId))];
|
||||||
if (destinationIds.length > 0) {
|
if (destinationIds.length > 0) {
|
||||||
const destinations = await db.query.notificationDestinationsTable.findMany({
|
const destinations = await db.query.notificationDestinationsTable.findMany({
|
||||||
where: and(
|
where: {
|
||||||
inArray(notificationDestinationsTable.id, destinationIds),
|
AND: [{ id: { in: destinationIds } }, { organizationId }],
|
||||||
eq(notificationDestinationsTable.organizationId, organizationId),
|
},
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (destinations.length !== destinationIds.length) {
|
if (destinations.length !== destinationIds.length) {
|
||||||
|
|
@ -338,7 +333,7 @@ const sendBackupNotification = async (
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
|
|
||||||
const assignments = await db.query.backupScheduleNotificationsTable.findMany({
|
const assignments = await db.query.backupScheduleNotificationsTable.findMany({
|
||||||
where: eq(backupScheduleNotificationsTable.scheduleId, scheduleId),
|
where: { scheduleId },
|
||||||
with: {
|
with: {
|
||||||
destination: true,
|
destination: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import { and, eq, or } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
|
import { ConflictError, InternalServerError, NotFoundError } from "http-errors-enhanced";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { repositoriesTable } from "../../db/schema";
|
import { repositoriesTable } from "../../db/schema";
|
||||||
|
|
@ -26,18 +26,15 @@ const runningDoctors = new Map<string, AbortController>();
|
||||||
const findRepository = async (idOrShortId: string) => {
|
const findRepository = async (idOrShortId: string) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
return await db.query.repositoriesTable.findFirst({
|
return await db.query.repositoriesTable.findFirst({
|
||||||
where: and(
|
where: {
|
||||||
or(eq(repositoriesTable.id, idOrShortId), eq(repositoriesTable.shortId, idOrShortId)),
|
AND: [{ OR: [{ id: idOrShortId }, { shortId: idOrShortId }] }, { organizationId }],
|
||||||
eq(repositoriesTable.organizationId, organizationId),
|
},
|
||||||
),
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const listRepositories = async () => {
|
const listRepositories = async () => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const repositories = await db.query.repositoriesTable.findMany({
|
const repositories = await db.query.repositoriesTable.findMany({ where: { organizationId } });
|
||||||
where: eq(repositoriesTable.organizationId, organizationId),
|
|
||||||
});
|
|
||||||
return repositories;
|
return repositories;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { systemService } from "./system.service";
|
import { systemService } from "./system.service";
|
||||||
import { requireAuth, requireOrgAdmin } from "../auth/auth.middleware";
|
import { requireAuth, requireOrgAdmin } from "../auth/auth.middleware";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { organization, usersTable } from "../../db/schema";
|
import { usersTable } from "../../db/schema";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { verifyUserPassword } from "../auth/helpers";
|
import { verifyUserPassword } from "../auth/helpers";
|
||||||
import { cryptoUtils } from "../../utils/crypto";
|
import { cryptoUtils } from "../../utils/crypto";
|
||||||
|
|
@ -78,9 +78,7 @@ export const systemController = new Hono()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const org = await db.query.organization.findFirst({
|
const org = await db.query.organization.findFirst({ where: { id: organizationId } });
|
||||||
where: eq(organization.id, organizationId),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!org?.metadata?.resticPassword) {
|
if (!org?.metadata?.resticPassword) {
|
||||||
return c.json({ message: "Organization Restic password not found" }, 404);
|
return c.json({ message: "Organization Restic password not found" }, 404);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { cache } from "../../utils/cache";
|
||||||
import { logger } from "~/server/utils/logger";
|
import { logger } from "~/server/utils/logger";
|
||||||
import { db } from "../../db/db";
|
import { db } from "../../db/db";
|
||||||
import { appMetadataTable } from "../../db/schema";
|
import { appMetadataTable } from "../../db/schema";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
import { REGISTRATION_ENABLED_KEY } from "~/client/lib/constants";
|
||||||
|
|
||||||
const CACHE_TTL = 60 * 60;
|
const CACHE_TTL = 60 * 60;
|
||||||
|
|
@ -91,7 +90,7 @@ const getUpdates = async (): Promise<UpdateInfoDto> => {
|
||||||
|
|
||||||
const isRegistrationEnabled = async () => {
|
const isRegistrationEnabled = async () => {
|
||||||
const result = await db.query.appMetadataTable.findFirst({
|
const result = await db.query.appMetadataTable.findFirst({
|
||||||
where: eq(appMetadataTable.key, REGISTRATION_ENABLED_KEY),
|
where: { key: REGISTRATION_ENABLED_KEY },
|
||||||
});
|
});
|
||||||
|
|
||||||
return result?.value === "true";
|
return result?.value === "true";
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ async function encryptSensitiveFields(config: BackendConfig): Promise<BackendCon
|
||||||
const listVolumes = async () => {
|
const listVolumes = async () => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const volumes = await db.query.volumesTable.findMany({
|
const volumes = await db.query.volumesTable.findMany({
|
||||||
where: eq(volumesTable.organizationId, organizationId),
|
where: { organizationId: organizationId },
|
||||||
});
|
});
|
||||||
|
|
||||||
return volumes;
|
return volumes;
|
||||||
|
|
@ -56,10 +56,12 @@ const findVolume = async (idOrShortId: string | number) => {
|
||||||
const organizationId = getOrganizationId();
|
const organizationId = getOrganizationId();
|
||||||
const isNumeric = typeof idOrShortId === "number" || /^\d+$/.test(String(idOrShortId));
|
const isNumeric = typeof idOrShortId === "number" || /^\d+$/.test(String(idOrShortId));
|
||||||
return await db.query.volumesTable.findFirst({
|
return await db.query.volumesTable.findFirst({
|
||||||
where: and(
|
where: {
|
||||||
isNumeric ? eq(volumesTable.id, Number(idOrShortId)) : eq(volumesTable.shortId, idOrShortId),
|
AND: [
|
||||||
eq(volumesTable.organizationId, organizationId),
|
isNumeric ? { id: Number(idOrShortId) } : { shortId: String(idOrShortId) },
|
||||||
),
|
{ organizationId: organizationId },
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import path from "node:path";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import { throttle } from "es-toolkit";
|
import { throttle } from "es-toolkit";
|
||||||
import { type } from "arktype";
|
import { type } from "arktype";
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { REPOSITORY_BASE, RESTIC_PASS_FILE, DEFAULT_EXCLUDES, RESTIC_CACHE_DIR } from "../core/constants";
|
import { REPOSITORY_BASE, RESTIC_PASS_FILE, DEFAULT_EXCLUDES, RESTIC_CACHE_DIR } from "../core/constants";
|
||||||
import { config as appConfig } from "../core/config";
|
import { config as appConfig } from "../core/config";
|
||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
|
|
@ -14,7 +13,6 @@ import { safeSpawn, exec } from "./spawn";
|
||||||
import type { CompressionMode, RepositoryConfig, OverwriteMode, BandwidthLimit } from "~/schemas/restic";
|
import type { CompressionMode, RepositoryConfig, OverwriteMode, BandwidthLimit } from "~/schemas/restic";
|
||||||
import { ResticError } from "./errors";
|
import { ResticError } from "./errors";
|
||||||
import { db } from "../db/db";
|
import { db } from "../db/db";
|
||||||
import { organization } from "../db/schema";
|
|
||||||
|
|
||||||
const backupOutputSchema = type({
|
const backupOutputSchema = type({
|
||||||
message_type: "'summary'",
|
message_type: "'summary'",
|
||||||
|
|
@ -110,9 +108,7 @@ export const buildEnv = async (config: RepositoryConfig, organizationId: string)
|
||||||
await fs.writeFile(passwordFilePath, decryptedPassword, { mode: 0o600 });
|
await fs.writeFile(passwordFilePath, decryptedPassword, { mode: 0o600 });
|
||||||
env.RESTIC_PASSWORD_FILE = passwordFilePath;
|
env.RESTIC_PASSWORD_FILE = passwordFilePath;
|
||||||
} else {
|
} else {
|
||||||
const org = await db.query.organization.findFirst({
|
const org = await db.query.organization.findFirst({ where: { id: organizationId } });
|
||||||
where: eq(organization.id, organizationId),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new Error(`Organization ${organizationId} not found`);
|
throw new Error(`Organization ${organizationId} not found`);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const createTestOrganization = async (overrides: Partial<typeof organizat
|
||||||
};
|
};
|
||||||
|
|
||||||
const existing = await db.query.organization.findFirst({
|
const existing = await db.query.organization.findFirst({
|
||||||
where: (o, { eq }) => eq(o.id, org.id ?? TEST_ORG_ID),
|
where: { id: org.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ import { createClient } from "@libsql/client";
|
||||||
import { drizzle } from "drizzle-orm/libsql";
|
import { drizzle } from "drizzle-orm/libsql";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { DATABASE_URL } from "~/server/core/constants";
|
import { DATABASE_URL } from "~/server/core/constants";
|
||||||
import * as schema from "~/server/db/schema";
|
import { relations } from "~/server/db/relations";
|
||||||
|
|
||||||
const sqlite = createClient({ url: `file:${path.join(process.cwd(), "playwright", DATABASE_URL)}` });
|
const sqlite = createClient({ url: `file:${path.join(process.cwd(), "playwright", DATABASE_URL)}` });
|
||||||
|
|
||||||
export const db = drizzle({ client: sqlite, schema: schema });
|
export const db = drizzle({ client: sqlite, relations: relations });
|
||||||
|
|
||||||
export const resetDatabase = async () => {
|
export const resetDatabase = async () => {
|
||||||
const cursor = await sqlite.execute("SELECT name FROM sqlite_master WHERE type='table'");
|
const cursor = await sqlite.execute("SELECT name FROM sqlite_master WHERE type='table'");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue