mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-23 05:16:38 +00:00
Compare commits
4 Commits
1.0.0-beta
...
1.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
722b877ea5 | ||
|
|
a9477d7eb9 | ||
|
|
bb5573a8f4 | ||
|
|
57cd776c34 |
@@ -4,7 +4,7 @@ export const passwordSchema = z
|
|||||||
.string()
|
.string()
|
||||||
.min(8, { message: "Password must be at least 8 characters long" })
|
.min(8, { message: "Password must be at least 8 characters long" })
|
||||||
.max(64, { message: "Password must be at most 64 characters long" })
|
.max(64, { message: "Password must be at most 64 characters long" })
|
||||||
.regex(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).*$/, {
|
.regex(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[,#?!@$%^&*-]).*$/, {
|
||||||
message: `Your password must meet the following conditions:
|
message: `Your password must meet the following conditions:
|
||||||
at least one uppercase English letter,
|
at least one uppercase English letter,
|
||||||
at least one lowercase English letter,
|
at least one lowercase English letter,
|
||||||
|
|||||||
@@ -118,14 +118,6 @@ export async function traefikConfigProvider(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
targets.filter(
|
|
||||||
(target: Target) => target.internalPort != null
|
|
||||||
).length == 0
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add routers and services empty objects if they don't exist
|
// add routers and services empty objects if they don't exist
|
||||||
if (!config_output.http.routers) {
|
if (!config_output.http.routers) {
|
||||||
config_output.http.routers = {};
|
config_output.http.routers = {};
|
||||||
@@ -156,7 +148,8 @@ export async function traefikConfigProvider(
|
|||||||
: {})
|
: {})
|
||||||
};
|
};
|
||||||
|
|
||||||
const additionalMiddlewares = config.getRawConfig().traefik.additional_middlewares || [];
|
const additionalMiddlewares =
|
||||||
|
config.getRawConfig().traefik.additional_middlewares || [];
|
||||||
|
|
||||||
config_output.http.routers![routerName] = {
|
config_output.http.routers![routerName] = {
|
||||||
entryPoints: [
|
entryPoints: [
|
||||||
@@ -164,7 +157,10 @@ export async function traefikConfigProvider(
|
|||||||
? config.getRawConfig().traefik.https_entrypoint
|
? config.getRawConfig().traefik.https_entrypoint
|
||||||
: config.getRawConfig().traefik.http_entrypoint
|
: config.getRawConfig().traefik.http_entrypoint
|
||||||
],
|
],
|
||||||
middlewares: [badgerMiddlewareName, ...additionalMiddlewares],
|
middlewares: [
|
||||||
|
badgerMiddlewareName,
|
||||||
|
...additionalMiddlewares
|
||||||
|
],
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
rule: `Host(\`${fullDomain}\`)`,
|
rule: `Host(\`${fullDomain}\`)`,
|
||||||
...(resource.ssl ? { tls } : {})
|
...(resource.ssl ? { tls } : {})
|
||||||
@@ -184,9 +180,31 @@ export async function traefikConfigProvider(
|
|||||||
config_output.http.services![serviceName] = {
|
config_output.http.services![serviceName] = {
|
||||||
loadBalancer: {
|
loadBalancer: {
|
||||||
servers: targets
|
servers: targets
|
||||||
.filter(
|
.filter((target: Target) => {
|
||||||
(target: Target) => target.internalPort != null
|
if (!target.enabled) {
|
||||||
)
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
site.type === "local" ||
|
||||||
|
site.type === "wireguard"
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!target.ip ||
|
||||||
|
!target.port ||
|
||||||
|
!target.method
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (site.type === "newt") {
|
||||||
|
if (
|
||||||
|
!target.internalPort ||
|
||||||
|
!target.method
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
.map((target: Target) => {
|
.map((target: Target) => {
|
||||||
if (
|
if (
|
||||||
site.type === "local" ||
|
site.type === "local" ||
|
||||||
@@ -213,14 +231,6 @@ export async function traefikConfigProvider(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
targets.filter(
|
|
||||||
(target: Target) => target.internalPort != null
|
|
||||||
).length == 0
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config_output[protocol]) {
|
if (!config_output[protocol]) {
|
||||||
config_output[protocol] = {
|
config_output[protocol] = {
|
||||||
routers: {},
|
routers: {},
|
||||||
@@ -237,9 +247,24 @@ export async function traefikConfigProvider(
|
|||||||
config_output[protocol].services[serviceName] = {
|
config_output[protocol].services[serviceName] = {
|
||||||
loadBalancer: {
|
loadBalancer: {
|
||||||
servers: targets
|
servers: targets
|
||||||
.filter(
|
.filter((target: Target) => {
|
||||||
(target: Target) => target.internalPort != null
|
if (!target.enabled) {
|
||||||
)
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
site.type === "local" ||
|
||||||
|
site.type === "wireguard"
|
||||||
|
) {
|
||||||
|
if (!target.ip || !target.port) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (site.type === "newt") {
|
||||||
|
if (!target.internalPort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
.map((target: Target) => {
|
.map((target: Target) => {
|
||||||
if (
|
if (
|
||||||
site.type === "local" ||
|
site.type === "local" ||
|
||||||
@@ -261,9 +286,9 @@ export async function traefikConfigProvider(
|
|||||||
}
|
}
|
||||||
return res.status(HttpCode.OK).json(config_output);
|
return res.status(HttpCode.OK).json(config_output);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`Failed to build traefik config: ${e}`);
|
logger.error(`Failed to build Traefik config: ${e}`);
|
||||||
return res.status(HttpCode.INTERNAL_SERVER_ERROR).json({
|
return res.status(HttpCode.INTERNAL_SERVER_ERROR).json({
|
||||||
error: "Failed to build traefik config"
|
error: "Failed to build Traefik config"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import db, { exists } from "@server/db";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
import { versionMigrations } from "@server/db/schema";
|
import { versionMigrations } from "@server/db/schema";
|
||||||
import { desc } from "drizzle-orm";
|
|
||||||
import { __DIRNAME } from "@server/lib/consts";
|
import { __DIRNAME } from "@server/lib/consts";
|
||||||
import { loadAppVersion } from "@server/lib/loadAppVersion";
|
import { loadAppVersion } from "@server/lib/loadAppVersion";
|
||||||
|
import { SqliteError } from "better-sqlite3";
|
||||||
import m1 from "./scripts/1.0.0-beta1";
|
import m1 from "./scripts/1.0.0-beta1";
|
||||||
import m2 from "./scripts/1.0.0-beta2";
|
import m2 from "./scripts/1.0.0-beta2";
|
||||||
import m3 from "./scripts/1.0.0-beta3";
|
import m3 from "./scripts/1.0.0-beta3";
|
||||||
@@ -53,38 +53,44 @@ export async function runMigrations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.insert(versionMigrations)
|
.insert(versionMigrations)
|
||||||
.values({
|
.values({
|
||||||
version: appVersion,
|
version: appVersion,
|
||||||
executedAt: Date.now()
|
executedAt: Date.now()
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Error running migrations:", e);
|
console.error("Error running migrations:", e);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000 * 60 * 60 * 24 * 1));
|
await new Promise((resolve) =>
|
||||||
|
setTimeout(resolve, 1000 * 60 * 60 * 24 * 1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeScripts() {
|
async function executeScripts() {
|
||||||
try {
|
try {
|
||||||
// Get the last executed version from the database
|
// Get the last executed version from the database
|
||||||
const lastExecuted = await db
|
const lastExecuted = await db.select().from(versionMigrations);
|
||||||
.select()
|
|
||||||
.from(versionMigrations)
|
|
||||||
.orderBy(desc(versionMigrations.version))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
const startVersion = lastExecuted[0]?.version ?? "0.0.0";
|
|
||||||
console.log(`Starting migrations from version ${startVersion}`);
|
|
||||||
|
|
||||||
// Filter and sort migrations
|
// Filter and sort migrations
|
||||||
const pendingMigrations = migrations
|
const pendingMigrations = lastExecuted
|
||||||
.filter((migration) => semver.gt(migration.version, startVersion))
|
.map((m) => m)
|
||||||
.sort((a, b) => semver.compare(a.version, b.version));
|
.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
|
// Run migrations in order
|
||||||
for (const migration of pendingMigrations) {
|
for (const migration of migrationsToRun) {
|
||||||
console.log(`Running migration ${migration.version}`);
|
console.log(`Running migration ${migration.version}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -102,12 +108,16 @@ async function executeScripts() {
|
|||||||
console.log(
|
console.log(
|
||||||
`Successfully completed migration ${migration.version}`
|
`Successfully completed migration ${migration.version}`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
|
if (e instanceof SqliteError && e.code === "SQLITE_CONSTRAINT_UNIQUE") {
|
||||||
|
console.error("Migration has already run! Skipping...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
console.error(
|
console.error(
|
||||||
`Failed to run migration ${migration.version}:`,
|
`Failed to run migration ${migration.version}:`,
|
||||||
error
|
e
|
||||||
);
|
);
|
||||||
throw error; // Re-throw to stop migration process
|
throw e; // Re-throw to stop migration process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,8 +164,6 @@ export default function CreateResourceForm({
|
|||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
async function onSubmit(data: CreateResourceFormValues) {
|
async function onSubmit(data: CreateResourceFormValues) {
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
.put<AxiosResponse<Resource>>(
|
.put<AxiosResponse<Resource>>(
|
||||||
`/org/${orgId}/site/${data.siteId}/resource/`,
|
`/org/${orgId}/site/${data.siteId}/resource/`,
|
||||||
@@ -194,16 +192,16 @@ export default function CreateResourceForm({
|
|||||||
setResourceId(id);
|
setResourceId(id);
|
||||||
|
|
||||||
if (data.http) {
|
if (data.http) {
|
||||||
goToResource();
|
goToResource(id);
|
||||||
} else {
|
} else {
|
||||||
setShowSnippets(true);
|
setShowSnippets(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToResource() {
|
function goToResource(id?: number) {
|
||||||
// navigate to the resource page
|
// navigate to the resource page
|
||||||
router.push(`/${orgId}/settings/resources/${resourceId}`);
|
router.push(`/${orgId}/settings/resources/${id || resourceId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user