mirror of
https://github.com/andwati/dokploy.git
synced 2026-11-08 13:05:17 +00:00
feat: implement utility functions to streamline owner selection for backups and domains
This commit is contained in:
@@ -276,6 +276,18 @@ function ownerFrom(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Picks the first non-null relation out of several mutually-exclusive owner candidates.
|
||||||
|
// Shared by backups, volume backups, and domains — all resolve "which one of these
|
||||||
|
// nullable relations is actually set" the same way.
|
||||||
|
function pickFirst<TRow, TType extends string>(
|
||||||
|
candidates: Array<[row: TRow | null | undefined, id: string | undefined, type: TType]>,
|
||||||
|
): [TRow, string, TType] | null {
|
||||||
|
for (const [row, id, type] of candidates) {
|
||||||
|
if (row && id) return [row, id, type];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function pickBackupOwner(backup: {
|
function pickBackupOwner(backup: {
|
||||||
postgres?: (OwnerRow & { postgresId: string }) | null;
|
postgres?: (OwnerRow & { postgresId: string }) | null;
|
||||||
mariadb?: (OwnerRow & { mariadbId: string }) | null;
|
mariadb?: (OwnerRow & { mariadbId: string }) | null;
|
||||||
@@ -284,19 +296,15 @@ function pickBackupOwner(backup: {
|
|||||||
libsql?: (OwnerRow & { libsqlId: string }) | null;
|
libsql?: (OwnerRow & { libsqlId: string }) | null;
|
||||||
compose?: (OwnerRow & { composeId: string }) | null;
|
compose?: (OwnerRow & { composeId: string }) | null;
|
||||||
}): Owner | null {
|
}): Owner | null {
|
||||||
if (backup.postgres)
|
const found = pickFirst<OwnerRow, OverviewServiceType>([
|
||||||
return ownerFrom(backup.postgres, backup.postgres.postgresId, "postgres");
|
[backup.postgres, backup.postgres?.postgresId, "postgres"],
|
||||||
if (backup.mariadb)
|
[backup.mariadb, backup.mariadb?.mariadbId, "mariadb"],
|
||||||
return ownerFrom(backup.mariadb, backup.mariadb.mariadbId, "mariadb");
|
[backup.mysql, backup.mysql?.mysqlId, "mysql"],
|
||||||
if (backup.mysql)
|
[backup.mongo, backup.mongo?.mongoId, "mongo"],
|
||||||
return ownerFrom(backup.mysql, backup.mysql.mysqlId, "mysql");
|
[backup.libsql, backup.libsql?.libsqlId, "libsql"],
|
||||||
if (backup.mongo)
|
[backup.compose, backup.compose?.composeId, "compose"],
|
||||||
return ownerFrom(backup.mongo, backup.mongo.mongoId, "mongo");
|
]);
|
||||||
if (backup.libsql)
|
return found ? ownerFrom(...found) : null;
|
||||||
return ownerFrom(backup.libsql, backup.libsql.libsqlId, "libsql");
|
|
||||||
if (backup.compose)
|
|
||||||
return ownerFrom(backup.compose, backup.compose.composeId, "compose");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickVolumeBackupOwner(volumeBackup: {
|
function pickVolumeBackupOwner(volumeBackup: {
|
||||||
@@ -309,43 +317,17 @@ function pickVolumeBackupOwner(volumeBackup: {
|
|||||||
libsql?: (OwnerRow & { libsqlId: string }) | null;
|
libsql?: (OwnerRow & { libsqlId: string }) | null;
|
||||||
compose?: (OwnerRow & { composeId: string }) | null;
|
compose?: (OwnerRow & { composeId: string }) | null;
|
||||||
}): Owner | null {
|
}): Owner | null {
|
||||||
if (volumeBackup.application)
|
const found = pickFirst<OwnerRow, OverviewServiceType>([
|
||||||
return ownerFrom(
|
[volumeBackup.application, volumeBackup.application?.applicationId, "application"],
|
||||||
volumeBackup.application,
|
[volumeBackup.postgres, volumeBackup.postgres?.postgresId, "postgres"],
|
||||||
volumeBackup.application.applicationId,
|
[volumeBackup.mariadb, volumeBackup.mariadb?.mariadbId, "mariadb"],
|
||||||
"application",
|
[volumeBackup.mysql, volumeBackup.mysql?.mysqlId, "mysql"],
|
||||||
);
|
[volumeBackup.mongo, volumeBackup.mongo?.mongoId, "mongo"],
|
||||||
if (volumeBackup.postgres)
|
[volumeBackup.redis, volumeBackup.redis?.redisId, "redis"],
|
||||||
return ownerFrom(
|
[volumeBackup.libsql, volumeBackup.libsql?.libsqlId, "libsql"],
|
||||||
volumeBackup.postgres,
|
[volumeBackup.compose, volumeBackup.compose?.composeId, "compose"],
|
||||||
volumeBackup.postgres.postgresId,
|
]);
|
||||||
"postgres",
|
return found ? ownerFrom(...found) : null;
|
||||||
);
|
|
||||||
if (volumeBackup.mariadb)
|
|
||||||
return ownerFrom(
|
|
||||||
volumeBackup.mariadb,
|
|
||||||
volumeBackup.mariadb.mariadbId,
|
|
||||||
"mariadb",
|
|
||||||
);
|
|
||||||
if (volumeBackup.mysql)
|
|
||||||
return ownerFrom(volumeBackup.mysql, volumeBackup.mysql.mysqlId, "mysql");
|
|
||||||
if (volumeBackup.mongo)
|
|
||||||
return ownerFrom(volumeBackup.mongo, volumeBackup.mongo.mongoId, "mongo");
|
|
||||||
if (volumeBackup.redis)
|
|
||||||
return ownerFrom(volumeBackup.redis, volumeBackup.redis.redisId, "redis");
|
|
||||||
if (volumeBackup.libsql)
|
|
||||||
return ownerFrom(
|
|
||||||
volumeBackup.libsql,
|
|
||||||
volumeBackup.libsql.libsqlId,
|
|
||||||
"libsql",
|
|
||||||
);
|
|
||||||
if (volumeBackup.compose)
|
|
||||||
return ownerFrom(
|
|
||||||
volumeBackup.compose,
|
|
||||||
volumeBackup.compose.composeId,
|
|
||||||
"compose",
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ownerless backups (e.g. the Dokploy host's own database) are visible to everyone.
|
// Ownerless backups (e.g. the Dokploy host's own database) are visible to everyone.
|
||||||
@@ -645,6 +627,17 @@ function domainOwnerFrom(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same scoping rule as ownerAccessCondition, just without the "ownerless rows are public" OR branch.
|
||||||
|
function orgScopeCondition(
|
||||||
|
orgId: string,
|
||||||
|
idColumn: AnyPgColumn,
|
||||||
|
accessedServices: string[] | null,
|
||||||
|
) {
|
||||||
|
return accessedServices !== null
|
||||||
|
? and(eq(projects.organizationId, orgId), inArray(idColumn, accessedServices))
|
||||||
|
: eq(projects.organizationId, orgId);
|
||||||
|
}
|
||||||
|
|
||||||
// Preview domains inherit access from their parent application, so they're scoped by the same accessedServices check as applications.
|
// Preview domains inherit access from their parent application, so they're scoped by the same accessedServices check as applications.
|
||||||
async function getDomainScopeIdsInOrg(
|
async function getDomainScopeIdsInOrg(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
@@ -660,12 +653,7 @@ async function getDomainScopeIdsInOrg(
|
|||||||
)
|
)
|
||||||
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
||||||
.where(
|
.where(
|
||||||
accessedServices !== null
|
orgScopeCondition(orgId, applications.applicationId, accessedServices),
|
||||||
? and(
|
|
||||||
eq(projects.organizationId, orgId),
|
|
||||||
inArray(applications.applicationId, accessedServices),
|
|
||||||
)
|
|
||||||
: eq(projects.organizationId, orgId),
|
|
||||||
),
|
),
|
||||||
db
|
db
|
||||||
.select({ id: compose.composeId })
|
.select({ id: compose.composeId })
|
||||||
@@ -675,14 +663,7 @@ async function getDomainScopeIdsInOrg(
|
|||||||
eq(compose.environmentId, environments.environmentId),
|
eq(compose.environmentId, environments.environmentId),
|
||||||
)
|
)
|
||||||
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
||||||
.where(
|
.where(orgScopeCondition(orgId, compose.composeId, accessedServices)),
|
||||||
accessedServices !== null
|
|
||||||
? and(
|
|
||||||
eq(projects.organizationId, orgId),
|
|
||||||
inArray(compose.composeId, accessedServices),
|
|
||||||
)
|
|
||||||
: eq(projects.organizationId, orgId),
|
|
||||||
),
|
|
||||||
db
|
db
|
||||||
.select({ id: previewDeployments.previewDeploymentId })
|
.select({ id: previewDeployments.previewDeploymentId })
|
||||||
.from(previewDeployments)
|
.from(previewDeployments)
|
||||||
@@ -696,12 +677,7 @@ async function getDomainScopeIdsInOrg(
|
|||||||
)
|
)
|
||||||
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
.innerJoin(projects, eq(environments.projectId, projects.projectId))
|
||||||
.where(
|
.where(
|
||||||
accessedServices !== null
|
orgScopeCondition(orgId, applications.applicationId, accessedServices),
|
||||||
? and(
|
|
||||||
eq(projects.organizationId, orgId),
|
|
||||||
inArray(applications.applicationId, accessedServices),
|
|
||||||
)
|
|
||||||
: eq(projects.organizationId, orgId),
|
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -765,21 +741,16 @@ export const getAllDomainsForOrganization = async (
|
|||||||
|
|
||||||
const result: OverviewDomain[] = [];
|
const result: OverviewDomain[] = [];
|
||||||
for (const domain of rows) {
|
for (const domain of rows) {
|
||||||
const owner = domain.application
|
const foundOwner = pickFirst<DomainOwnerRow, OverviewDomainOwnerType>([
|
||||||
? domainOwnerFrom(
|
[domain.application, domain.application?.applicationId, "application"],
|
||||||
domain.application,
|
[domain.compose, domain.compose?.composeId, "compose"],
|
||||||
domain.application.applicationId,
|
[
|
||||||
"application",
|
domain.previewDeployment?.application,
|
||||||
)
|
domain.previewDeployment?.application?.applicationId,
|
||||||
: domain.compose
|
"application",
|
||||||
? domainOwnerFrom(domain.compose, domain.compose.composeId, "compose")
|
],
|
||||||
: domain.previewDeployment?.application
|
]);
|
||||||
? domainOwnerFrom(
|
const owner = foundOwner ? domainOwnerFrom(...foundOwner) : null;
|
||||||
domain.previewDeployment.application,
|
|
||||||
domain.previewDeployment.application.applicationId,
|
|
||||||
"application",
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (!owner || owner.organizationId !== orgId) continue;
|
if (!owner || owner.organizationId !== orgId) continue;
|
||||||
if (accessedServices !== null && !accessedServices.includes(owner.id)) {
|
if (accessedServices !== null && !accessedServices.includes(owner.id)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user