mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-05 02:24:59 +02:00
support postgresql as database option
This commit is contained in:
parent
62a0104e70
commit
2cca561e51
218 changed files with 1417 additions and 713 deletions
|
@ -8,7 +8,7 @@ import {
|
|||
resourceSessions,
|
||||
sessions,
|
||||
userInvites
|
||||
} from "@server/db/schemas";
|
||||
} from "@server/db";
|
||||
import logger from "@server/logger";
|
||||
import { lt } from "drizzle-orm";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { db } from "@server/db";
|
||||
import { domains, exitNodes, orgDomains, orgs, resources } from "../db/schemas/schema";
|
||||
import { domains, exitNodes, orgDomains, orgs, resources } from "@server/db";
|
||||
import config from "@server/lib/config";
|
||||
import { eq, ne } from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { ActionsEnum } from "@server/auth/actions";
|
||||
import { db } from "@server/db";
|
||||
import { actions, roles, roleActions } from "../db/schemas/schema";
|
||||
import { actions, roles, roleActions } from "@server/db";
|
||||
import { eq, inArray } from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
|
||||
|
@ -22,85 +22,37 @@ export async function ensureActions() {
|
|||
.where(eq(roles.isAdmin, true))
|
||||
.execute();
|
||||
|
||||
await db.transaction(async (trx) => {
|
||||
await db.transaction(async (trx) => {
|
||||
// Add new actions
|
||||
for (const actionId of actionsToAdd) {
|
||||
logger.debug(`Adding action: ${actionId}`);
|
||||
await trx.insert(actions).values({ actionId }).execute();
|
||||
// Add new actions to the Default role
|
||||
if (defaultRoles.length != 0) {
|
||||
await trx
|
||||
.insert(roleActions)
|
||||
.values(
|
||||
defaultRoles.map((role) => ({
|
||||
roleId: role.roleId!,
|
||||
actionId,
|
||||
orgId: role.orgId!
|
||||
}))
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Add new actions
|
||||
for (const actionId of actionsToAdd) {
|
||||
logger.debug(`Adding action: ${actionId}`);
|
||||
await trx.insert(actions).values({ actionId }).execute();
|
||||
// Add new actions to the Default role
|
||||
if (defaultRoles.length != 0) {
|
||||
// Remove deprecated actions
|
||||
if (actionsToRemove.length > 0) {
|
||||
logger.debug(`Removing actions: ${actionsToRemove.join(", ")}`);
|
||||
await trx
|
||||
.insert(roleActions)
|
||||
.values(
|
||||
defaultRoles.map((role) => ({
|
||||
roleId: role.roleId!,
|
||||
actionId,
|
||||
orgId: role.orgId!
|
||||
}))
|
||||
)
|
||||
.delete(actions)
|
||||
.where(inArray(actions.actionId, actionsToRemove))
|
||||
.execute();
|
||||
await trx
|
||||
.delete(roleActions)
|
||||
.where(inArray(roleActions.actionId, actionsToRemove))
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deprecated actions
|
||||
if (actionsToRemove.length > 0) {
|
||||
logger.debug(`Removing actions: ${actionsToRemove.join(", ")}`);
|
||||
await trx
|
||||
.delete(actions)
|
||||
.where(inArray(actions.actionId, actionsToRemove))
|
||||
.execute();
|
||||
await trx
|
||||
.delete(roleActions)
|
||||
.where(inArray(roleActions.actionId, actionsToRemove))
|
||||
.execute();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function createAdminRole(orgId: string) {
|
||||
let roleId: any;
|
||||
await db.transaction(async (trx) => {
|
||||
|
||||
const [insertedRole] = await trx
|
||||
.insert(roles)
|
||||
.values({
|
||||
orgId,
|
||||
isAdmin: true,
|
||||
name: "Admin",
|
||||
description: "Admin role with the most permissions"
|
||||
})
|
||||
.returning({ roleId: roles.roleId })
|
||||
.execute();
|
||||
|
||||
if (!insertedRole || !insertedRole.roleId) {
|
||||
throw new Error("Failed to create Admin role");
|
||||
}
|
||||
|
||||
roleId = insertedRole.roleId;
|
||||
|
||||
const actionIds = await trx.select().from(actions).execute();
|
||||
|
||||
if (actionIds.length === 0) {
|
||||
logger.info("No actions to assign to the Admin role");
|
||||
return;
|
||||
}
|
||||
|
||||
await trx
|
||||
.insert(roleActions)
|
||||
.values(
|
||||
actionIds.map((action) => ({
|
||||
roleId,
|
||||
actionId: action.actionId,
|
||||
orgId
|
||||
}))
|
||||
)
|
||||
.execute();
|
||||
});
|
||||
|
||||
if (!roleId) {
|
||||
throw new Error("Failed to create Admin role");
|
||||
}
|
||||
|
||||
return roleId;
|
||||
}
|
||||
|
|
133
server/setup/migrationsPg.ts
Normal file
133
server/setup/migrationsPg.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||
import { db } from "../db/pg";
|
||||
import semver from "semver";
|
||||
import { versionMigrations } from "../db/pg";
|
||||
import { __DIRNAME, APP_PATH, APP_VERSION } from "@server/lib/consts";
|
||||
import path from "path";
|
||||
|
||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
||||
// EXCEPT FOR THE DATABASE AND THE SCHEMA
|
||||
|
||||
// Define the migration list with versions and their corresponding functions
|
||||
const migrations = [
|
||||
// Add new migrations here as they are created
|
||||
] as {
|
||||
version: string;
|
||||
run: () => Promise<void>;
|
||||
}[];
|
||||
|
||||
await run();
|
||||
|
||||
async function run() {
|
||||
// run the migrations
|
||||
await runMigrations();
|
||||
}
|
||||
|
||||
export async function runMigrations() {
|
||||
try {
|
||||
const appVersion = APP_VERSION;
|
||||
|
||||
// determine if the migrations table exists
|
||||
const exists = await db
|
||||
.select()
|
||||
.from(versionMigrations)
|
||||
.limit(1)
|
||||
.execute()
|
||||
.then((res) => res.length > 0)
|
||||
.catch(() => false);
|
||||
|
||||
if (exists) {
|
||||
console.log("Migrations table exists, running scripts...");
|
||||
await executeScripts();
|
||||
} else {
|
||||
console.log("Migrations table does not exist, creating it...");
|
||||
console.log("Running migrations...");
|
||||
try {
|
||||
await migrate(db, {
|
||||
migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build
|
||||
});
|
||||
console.log("Migrations completed successfully.");
|
||||
} catch (error) {
|
||||
console.error("Error running migrations:", error);
|
||||
}
|
||||
|
||||
await db
|
||||
.insert(versionMigrations)
|
||||
.values({
|
||||
version: appVersion,
|
||||
executedAt: Date.now()
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error running migrations:", e);
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, 1000 * 60 * 60 * 24 * 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function executeScripts() {
|
||||
try {
|
||||
// Get the last executed version from the database
|
||||
const lastExecuted = await db.select().from(versionMigrations);
|
||||
|
||||
// Filter and sort migrations
|
||||
const pendingMigrations = lastExecuted
|
||||
.map((m) => m)
|
||||
.sort((a, b) => semver.compare(b.version, a.version));
|
||||
const startVersion = pendingMigrations[0]?.version ?? "0.0.0";
|
||||
console.log(`Starting migrations from version ${startVersion}`);
|
||||
|
||||
const migrationsToRun = migrations.filter((migration) =>
|
||||
semver.gt(migration.version, startVersion)
|
||||
);
|
||||
|
||||
console.log(
|
||||
"Migrations to run:",
|
||||
migrationsToRun.map((m) => m.version).join(", ")
|
||||
);
|
||||
|
||||
// Run migrations in order
|
||||
for (const migration of migrationsToRun) {
|
||||
console.log(`Running migration ${migration.version}`);
|
||||
|
||||
try {
|
||||
await migration.run();
|
||||
|
||||
// Update version in database
|
||||
await db
|
||||
.insert(versionMigrations)
|
||||
.values({
|
||||
version: migration.version,
|
||||
executedAt: Date.now()
|
||||
})
|
||||
.execute();
|
||||
|
||||
console.log(
|
||||
`Successfully completed migration ${migration.version}`
|
||||
);
|
||||
} catch (e) {
|
||||
if (
|
||||
e instanceof Error &&
|
||||
typeof (e as any).code === "string" &&
|
||||
(e as any).code === "23505"
|
||||
) {
|
||||
console.error("Migration has already run! Skipping...");
|
||||
continue; // or return, depending on context
|
||||
}
|
||||
|
||||
console.error(
|
||||
`Failed to run migration ${migration.version}:`,
|
||||
e
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("All migrations completed successfully");
|
||||
} catch (error) {
|
||||
console.error("Migration process failed:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
|
@ -1,25 +1,25 @@
|
|||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import db, { exists } from "@server/db";
|
||||
import { db, exists } from "../db/sqlite";
|
||||
import path from "path";
|
||||
import semver from "semver";
|
||||
import { versionMigrations } from "@server/db/schemas";
|
||||
import { versionMigrations } from "../db/sqlite";
|
||||
import { __DIRNAME, APP_PATH, APP_VERSION } from "@server/lib/consts";
|
||||
import { SqliteError } from "better-sqlite3";
|
||||
import fs from "fs";
|
||||
import m1 from "./scripts/1.0.0-beta1";
|
||||
import m2 from "./scripts/1.0.0-beta2";
|
||||
import m3 from "./scripts/1.0.0-beta3";
|
||||
import m4 from "./scripts/1.0.0-beta5";
|
||||
import m5 from "./scripts/1.0.0-beta6";
|
||||
import m6 from "./scripts/1.0.0-beta9";
|
||||
import m7 from "./scripts/1.0.0-beta10";
|
||||
import m8 from "./scripts/1.0.0-beta12";
|
||||
import m13 from "./scripts/1.0.0-beta13";
|
||||
import m15 from "./scripts/1.0.0-beta15";
|
||||
import m16 from "./scripts/1.0.0";
|
||||
import m17 from "./scripts/1.1.0";
|
||||
import m18 from "./scripts/1.2.0";
|
||||
import m19 from "./scripts/1.3.0";
|
||||
import m1 from "./scriptsSqlite/1.0.0-beta1";
|
||||
import m2 from "./scriptsSqlite/1.0.0-beta2";
|
||||
import m3 from "./scriptsSqlite/1.0.0-beta3";
|
||||
import m4 from "./scriptsSqlite/1.0.0-beta5";
|
||||
import m5 from "./scriptsSqlite/1.0.0-beta6";
|
||||
import m6 from "./scriptsSqlite/1.0.0-beta9";
|
||||
import m7 from "./scriptsSqlite/1.0.0-beta10";
|
||||
import m8 from "./scriptsSqlite/1.0.0-beta12";
|
||||
import m13 from "./scriptsSqlite/1.0.0-beta13";
|
||||
import m15 from "./scriptsSqlite/1.0.0-beta15";
|
||||
import m16 from "./scriptsSqlite/1.0.0";
|
||||
import m17 from "./scriptsSqlite/1.1.0";
|
||||
import m18 from "./scriptsSqlite/1.2.0";
|
||||
import m19 from "./scriptsSqlite/1.3.0";
|
||||
import { setHostMeta } from "./setHostMeta";
|
||||
|
||||
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
|
|
@ -1,4 +1,4 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||
import { sql } from "drizzle-orm";
|
||||
import fs from "fs";
|
|
@ -1,4 +1,4 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
const version = "1.0.0-beta.13";
|
|
@ -1,9 +1,9 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import { configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||
import fs from "fs";
|
||||
import yaml from "js-yaml";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { domains, orgDomains, resources } from "@server/db/schemas";
|
||||
import { domains, orgDomains, resources } from "@server/db";
|
||||
|
||||
const version = "1.0.0-beta.15";
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import {
|
||||
emailVerificationCodes,
|
||||
passwordResetTokens,
|
||||
|
@ -8,7 +8,7 @@ import {
|
|||
targets,
|
||||
userInvites,
|
||||
users
|
||||
} from "@server/db/schemas";
|
||||
} from "../../db/sqlite";
|
||||
import { APP_PATH, configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import fs from "fs";
|
|
@ -1,4 +1,4 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
const version = "1.1.0";
|
|
@ -1,4 +1,4 @@
|
|||
import db from "@server/db";
|
||||
import { db } from "../../db/sqlite";
|
||||
import { APP_PATH, configFilePath1, configFilePath2 } from "@server/lib/consts";
|
||||
import { sql } from "drizzle-orm";
|
||||
import fs from "fs";
|
|
@ -1,5 +1,5 @@
|
|||
import db from "@server/db";
|
||||
import { hostMeta } from "@server/db/schemas";
|
||||
import { db } from "@server/db";
|
||||
import { hostMeta } from "@server/db";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
export async function setHostMeta() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { generateId, invalidateAllSessions } from "@server/auth/sessions/app";
|
||||
import { hashPassword, verifyPassword } from "@server/auth/password";
|
||||
import config from "@server/lib/config";
|
||||
import db from "@server/db";
|
||||
import { users } from "@server/db/schemas";
|
||||
import { db } from "@server/db";
|
||||
import { users } from "@server/db";
|
||||
import logger from "@server/logger";
|
||||
import { eq } from "drizzle-orm";
|
||||
import moment from "moment";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue