mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 00:28:12 +00:00
feat: completed ap, org roles and project roles and project membership
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types";
|
|
||||||
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
@@ -16,6 +15,7 @@ import {
|
|||||||
SanitizedIdentityPrivilegeSchema
|
SanitizedIdentityPrivilegeSchema
|
||||||
} from "@app/server/routes/sanitizedSchemas";
|
} from "@app/server/routes/sanitizedSchemas";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { AccessScope, MembershipActors, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
|
|
||||||
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -56,6 +56,10 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
if (!permissions && !privilegePermission) {
|
if (!permissions && !privilegePermission) {
|
||||||
throw new UnauthorizedError({ message: "Permission or privilegePermission must be provided" });
|
throw new UnauthorizedError({ message: "Permission or privilegePermission must be provided" });
|
||||||
}
|
}
|
||||||
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
slug: req.body.projectSlug
|
||||||
|
});
|
||||||
|
|
||||||
const permission = privilegePermission
|
const permission = privilegePermission
|
||||||
? privilegePermission.actions.map((action) => ({
|
? privilegePermission.actions.map((action) => ({
|
||||||
@@ -64,19 +68,35 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
conditions: privilegePermission.conditions
|
conditions: privilegePermission.conditions
|
||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.create({
|
|
||||||
actorId: req.permission.id,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorOrgId: req.permission.orgId,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
...req.body,
|
projectId,
|
||||||
slug: req.body.slug ?? slugify(alphaNumericNanoId(12)),
|
orgId: req.permission.orgId
|
||||||
isTemporary: false,
|
},
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
data: {
|
||||||
// @ts-ignore-error this is valid ts
|
actorId: req.body.identityId,
|
||||||
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
actorType: MembershipActors.Identity,
|
||||||
|
...req.body,
|
||||||
|
isTemporary: false,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore-error this is valid ts
|
||||||
|
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,7 +126,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.privilegePermission
|
IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.privilegePermission
|
||||||
).optional(),
|
).optional(),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -138,19 +158,39 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
|
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.create({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.body.projectSlug
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
...req.body,
|
|
||||||
slug: req.body.slug ?? slugify(alphaNumericNanoId(12)),
|
|
||||||
isTemporary: true,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore-error this is valid ts
|
|
||||||
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: MembershipActors.Identity,
|
||||||
|
...req.body,
|
||||||
|
isTemporary: true,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore-error this is valid ts
|
||||||
|
permissions: backfillPermissionV1SchemaToV2Schema(permission)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -183,7 +223,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
).optional(),
|
).optional(),
|
||||||
isTemporary: z.boolean().describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
isTemporary: z.boolean().describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -216,18 +256,43 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
conditions: privilegePermission.conditions
|
conditions: privilegePermission.conditions
|
||||||
}))
|
}))
|
||||||
: permissions!;
|
: permissions!;
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.updateBySlug({
|
|
||||||
actorId: req.permission.id,
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actor: req.permission.type,
|
orgId: req.permission.orgId,
|
||||||
actorOrgId: req.permission.orgId,
|
slug: req.body.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
});
|
||||||
slug: req.body.privilegeSlug,
|
|
||||||
identityId: req.body.identityId,
|
const { membershipId } = await server.services.convertor.identityIdToMembershipId(
|
||||||
projectSlug: req.body.projectSlug,
|
req.body.identityId,
|
||||||
|
AccessScope.Project,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { privilegeId } = await server.services.convertor.additionalPrivilegeNameToId(
|
||||||
|
req.body.privilegeSlug,
|
||||||
|
membershipId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: MembershipActors.Identity,
|
||||||
|
id: privilegeId
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
|
...req.body,
|
||||||
|
isTemporary: true,
|
||||||
...updatedInfo,
|
...updatedInfo,
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore-error this is valid ts
|
||||||
permissions: permission
|
permissions: permission
|
||||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore-error this is valid ts
|
// @ts-ignore-error this is valid ts
|
||||||
@@ -235,7 +300,16 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -267,16 +341,45 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.deleteBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.body.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.body.privilegeSlug,
|
|
||||||
identityId: req.body.identityId,
|
|
||||||
projectSlug: req.body.projectSlug
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { membershipId } = await server.services.convertor.identityIdToMembershipId(
|
||||||
|
req.body.identityId,
|
||||||
|
AccessScope.Project,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { privilegeId } = await server.services.convertor.additionalPrivilegeNameToId(
|
||||||
|
req.body.privilegeSlug,
|
||||||
|
membershipId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.body.identityId,
|
||||||
|
actorType: MembershipActors.Identity,
|
||||||
|
id: privilegeId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -310,15 +413,45 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilege.getPrivilegeDetailsBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
slug: req.query.projectSlug
|
||||||
actor: req.permission.type,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.params.privilegeSlug,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { membershipId } = await server.services.convertor.identityIdToMembershipId(
|
||||||
|
req.query.identityId,
|
||||||
|
AccessScope.Project,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { privilegeId } = await server.services.convertor.additionalPrivilegeNameToId(
|
||||||
|
req.params.privilegeSlug,
|
||||||
|
membershipId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: MembershipActors.Identity,
|
||||||
|
id: privilegeId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -349,15 +482,32 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.identityProjectAdditionalPrivilege.listIdentityProjectPrivileges({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
orgId: req.permission.orgId,
|
||||||
actor: req.permission.type,
|
slug: req.query.projectSlug
|
||||||
actorAuthMethod: req.permission.authMethod,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
privileges
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AccessScope, MembershipActors, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
|
|
||||||
import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -34,7 +34,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true),
|
isTemporary: z.literal(true),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -55,17 +55,31 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.create({
|
const { userId, membership } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.body.projectMembershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
projectMembershipId: req.body.projectMembershipId,
|
|
||||||
...req.body.type,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
slug: req.body.slug || slugify(alphaNumericNanoId(8)),
|
permission: req.permission,
|
||||||
permissions: req.body.permissions
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
actorId: userId,
|
||||||
|
actorType: MembershipActors.User,
|
||||||
|
...req.body.type,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
|
permissions: req.body.permissions
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: { ...privilege, userId, projectId: membership.scopeProjectId as string, slug: privilege.name }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,7 +105,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
isTemporary: z.literal(true).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -113,21 +127,43 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.updateById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.privilegeId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
...req.body,
|
|
||||||
...req.body.type,
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
permissions: req.body.permissions
|
permission: req.permission,
|
||||||
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
scopeData: {
|
||||||
// @ts-ignore-error this is valid ts
|
scope: AccessScope.Project,
|
||||||
req.body.permissions
|
projectId: membership.scopeProjectId as string,
|
||||||
: undefined,
|
orgId: req.permission.orgId
|
||||||
privilegeId: req.params.privilegeId
|
},
|
||||||
|
data: {
|
||||||
|
...req.body,
|
||||||
|
...req.body.type,
|
||||||
|
permissions: req.body.permissions
|
||||||
|
? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore-error this is valid ts
|
||||||
|
req.body.permissions
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: membership.actorUserId as string,
|
||||||
|
actorType: MembershipActors.User
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: membership.actorUserId as string,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -149,14 +185,34 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.deleteById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.privilegeId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
privilegeId: req.params.privilegeId
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: membership.actorUserId as string,
|
||||||
|
actorType: MembershipActors.User
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: membership.actorUserId as string,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -178,14 +234,33 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.projectUserAdditionalPrivilege.listPrivileges({
|
const { userId, membership } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.query.projectMembershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
projectMembershipId: req.query.projectMembershipId
|
|
||||||
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: userId,
|
||||||
|
actorType: MembershipActors.User
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privileges };
|
|
||||||
|
return {
|
||||||
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
userId: membership.actorUserId as string,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -207,14 +282,34 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.projectUserAdditionalPrivilege.getPrivilegeDetailsById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.privilegeId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
privilegeId: req.params.privilegeId
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.privilegeId,
|
||||||
|
actorId: membership.actorUserId as string,
|
||||||
|
actorType: MembershipActors.User
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
userId: membership.actorUserId as string,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-types";
|
import { AccessScope, MembershipActors, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs";
|
||||||
@@ -43,7 +43,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true),
|
isTemporary: z.literal(true),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.CREATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.CREATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -64,18 +64,31 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.create({
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.createAdditionalPrivilege({
|
||||||
actorAuthMethod: req.permission.authMethod,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorOrgId: req.permission.orgId,
|
scope: AccessScope.Project,
|
||||||
actor: req.permission.type,
|
projectId: req.body.projectId,
|
||||||
projectId: req.body.projectId,
|
orgId: req.permission.orgId
|
||||||
identityId: req.body.identityId,
|
},
|
||||||
...req.body.type,
|
data: {
|
||||||
slug: req.body.slug || slugify(alphaNumericNanoId(8)),
|
actorId: req.body.identityId,
|
||||||
permissions: req.body.permissions
|
actorType: MembershipActors.Identity,
|
||||||
|
...req.body.type,
|
||||||
|
name: req.body.slug || slugify(alphaNumericNanoId(8)),
|
||||||
|
permissions: req.body.permissions
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.body.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId: req.body.projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,7 +121,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(true).describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.isTemporary),
|
isTemporary: z.literal(true).describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.temporaryMode),
|
.describe(IDENTITY_ADDITIONAL_PRIVILEGE_V2.UPDATE.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -129,19 +142,40 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.updateById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.id,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
req.permission.orgId
|
||||||
actorAuthMethod: req.permission.authMethod,
|
);
|
||||||
id: req.params.id,
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.updateAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: membership.actorIdentityId as string,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
...req.body,
|
...req.body,
|
||||||
...req.body.type,
|
...req.body.type,
|
||||||
permissions: req.body.permissions || undefined
|
permissions: req.body.permissions || undefined
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: membership.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -171,14 +205,35 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.deleteById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.id,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
id: req.params.id
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.deleteAdditionalPrivilege({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: membership.actorIdentityId as string,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: membership.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -208,14 +263,35 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.getPrivilegeDetailsById({
|
const { membership } = await server.services.convertor.additionalPrivilegeIdToMembershipId(
|
||||||
actorId: req.permission.id,
|
req.params.id,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
AccessScope.Project,
|
||||||
actor: req.permission.type,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
id: req.params.id
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeById({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
id: req.params.id,
|
||||||
|
actorId: membership.actorIdentityId as string,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: membership.actorIdentityId as string,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId: membership.scopeProjectId as string,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,15 +325,36 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privilege = await server.services.identityProjectAdditionalPrivilegeV2.getPrivilegeDetailsBySlug({
|
const { id: projectId } = await server.services.convertor.projectSlugToId({
|
||||||
actorId: req.permission.id,
|
slug: req.query.projectSlug,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
orgId: req.permission.orgId
|
||||||
actor: req.permission.type,
|
|
||||||
actorOrgId: req.permission.orgId,
|
|
||||||
slug: req.params.privilegeSlug,
|
|
||||||
...req.query
|
|
||||||
});
|
});
|
||||||
return { privilege };
|
|
||||||
|
const { additionalPrivilege: privilege } = await server.services.additionalPrivilege.getAdditionalPrivilegeByName(
|
||||||
|
{
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
projectId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
name: req.params.privilegeSlug,
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
privilege: {
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -288,15 +385,27 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const privileges = await server.services.identityProjectAdditionalPrivilegeV2.listIdentityProjectPrivileges({
|
const { additionalPrivileges: privileges } = await server.services.additionalPrivilege.listAdditionalPrivileges({
|
||||||
actorId: req.permission.id,
|
permission: req.permission,
|
||||||
actor: req.permission.type,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
projectId: req.query.projectId,
|
||||||
...req.query
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
actorId: req.query.identityId,
|
||||||
|
actorType: MembershipActors.Identity
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
privileges
|
privileges: privileges.map((privilege) => ({
|
||||||
|
...privilege,
|
||||||
|
identityId: req.query.identityId,
|
||||||
|
projectMembershipId: privilege.membershipId,
|
||||||
|
projectId: req.query.projectId,
|
||||||
|
slug: privilege.name
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
ProjectMembershipsSchema,
|
ProjectMembershipsSchema,
|
||||||
ProjectUserMembershipRolesSchema,
|
ProjectUserMembershipRolesSchema,
|
||||||
|
TemporaryPermissionMode,
|
||||||
UserEncryptionKeysSchema,
|
UserEncryptionKeysSchema,
|
||||||
UsersSchema
|
UsersSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
@@ -14,7 +15,6 @@ import { ms } from "@app/lib/ms";
|
|||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types";
|
|
||||||
|
|
||||||
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -134,18 +134,34 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.projectMembership.getProjectMembershipById({
|
const { userId } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.params.membershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
projectId: req.params.projectId,
|
const membership = await server.services.membershipUser.getMembershipByUserId({
|
||||||
id: req.params.membershipId
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
userId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { membership };
|
|
||||||
|
return {
|
||||||
|
membership: {
|
||||||
|
...membership,
|
||||||
|
userId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO(simp): look into multi deletion and this as well
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/:projectId/memberships/details",
|
url: "/:projectId/memberships/details",
|
||||||
@@ -317,7 +333,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
z.object({
|
z.object({
|
||||||
role: z.string(),
|
role: z.string(),
|
||||||
isTemporary: z.literal(true),
|
isTemporary: z.literal(true),
|
||||||
temporaryMode: z.nativeEnum(ProjectUserMembershipTemporaryMode),
|
temporaryMode: z.nativeEnum(TemporaryPermissionMode),
|
||||||
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
|
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
|
||||||
temporaryAccessStartTime: z.string().datetime()
|
temporaryAccessStartTime: z.string().datetime()
|
||||||
})
|
})
|
||||||
@@ -335,17 +351,28 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.projectMembership.updateProjectMembership({
|
const { userId } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.params.membershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
projectId: req.params.projectId,
|
|
||||||
membershipId: req.params.membershipId,
|
const { membership } = await server.services.membershipUser.updateMembership({
|
||||||
roles: req.body.roles
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
roles: req.body.roles
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { roles };
|
return { roles: membership.roles.map((el) => ({ ...el, projectMembershipId: req.params.membershipId })) };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -443,13 +470,22 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.projectMembership.deleteProjectMembership({
|
const { userId } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.params.membershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
projectId: req.params.projectId,
|
|
||||||
membershipId: req.params.membershipId
|
const { membership } = await server.services.membershipUser.deleteMembership({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
userId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
@@ -458,12 +494,19 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
|||||||
event: {
|
event: {
|
||||||
type: EventType.REMOVE_PROJECT_MEMBER,
|
type: EventType.REMOVE_PROJECT_MEMBER,
|
||||||
metadata: {
|
metadata: {
|
||||||
userId: membership.userId,
|
userId: membership.actorUserId as string,
|
||||||
email: ""
|
email: ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { membership };
|
|
||||||
|
return {
|
||||||
|
membership: {
|
||||||
|
...membership,
|
||||||
|
userId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TAdditionalPrivilegeDALFactory = ReturnType<typeof additionalPrivilegeDALFactory>;
|
export type TAdditionalPrivilegeDALFactory = ReturnType<typeof additionalPrivilegeDALFactory>;
|
||||||
|
|
||||||
export const additionalPrivilegeDALFactory = (db: TDbClient) => {
|
export const additionalPrivilegeDALFactory = (db: TDbClient) => {
|
||||||
const orm = ormify(db, TableName.AdditionalPrivilege);
|
const orm = ormify(db, TableName.AdditionalPrivilege);
|
||||||
return orm;
|
|
||||||
|
const getMembershipById = async (privilegeId: string) => {
|
||||||
|
const doc = await db
|
||||||
|
.replicaNode()(TableName.AdditionalPrivilege)
|
||||||
|
.join(TableName.Membership, `${TableName.AdditionalPrivilege}.membershipId`, `${TableName.Membership}.id`)
|
||||||
|
.select(selectAllTableCols(TableName.Membership))
|
||||||
|
.where(`${TableName.AdditionalPrivilege}.id`, privilegeId)
|
||||||
|
.first();
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...orm, getMembershipById };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
TCreateAdditionalPrivilegesDTO,
|
TCreateAdditionalPrivilegesDTO,
|
||||||
TDeleteAdditionalPrivilegesDTO,
|
TDeleteAdditionalPrivilegesDTO,
|
||||||
TGetAdditionalPrivilegesByIdDTO,
|
TGetAdditionalPrivilegesByIdDTO,
|
||||||
|
TGetAdditionalPrivilegesByNameDTO,
|
||||||
TListAdditionalPrivilegesDTO,
|
TListAdditionalPrivilegesDTO,
|
||||||
TUpdateAdditionalPrivilegesDTO
|
TUpdateAdditionalPrivilegesDTO
|
||||||
} from "./additional-privilege-types";
|
} from "./additional-privilege-types";
|
||||||
@@ -71,7 +72,9 @@ export const additionalPrivilegeServiceFactory = ({
|
|||||||
permissions: JSON.stringify(packRules(data.permissions as RawRule[]))
|
permissions: JSON.stringify(packRules(data.permissions as RawRule[]))
|
||||||
});
|
});
|
||||||
|
|
||||||
return { additionalPrivilege: { ...additionalPrivilege, permissions: data.permissions } };
|
return {
|
||||||
|
additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.temporaryAccessStartTime || !data.temporaryRange) {
|
if (!data.temporaryAccessStartTime || !data.temporaryRange) {
|
||||||
@@ -92,7 +95,9 @@ export const additionalPrivilegeServiceFactory = ({
|
|||||||
temporaryRange: data.temporaryRange
|
temporaryRange: data.temporaryRange
|
||||||
});
|
});
|
||||||
|
|
||||||
return { additionalPrivilege: { ...additionalPrivilege, permissions: data.permissions } };
|
return {
|
||||||
|
additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) }
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateAdditionalPrivilege = async (dto: TUpdateAdditionalPrivilegesDTO) => {
|
const updateAdditionalPrivilege = async (dto: TUpdateAdditionalPrivilegesDTO) => {
|
||||||
@@ -169,7 +174,7 @@ export const additionalPrivilegeServiceFactory = ({
|
|||||||
const getAdditionalPrivilegeById = async (dto: TGetAdditionalPrivilegesByIdDTO) => {
|
const getAdditionalPrivilegeById = async (dto: TGetAdditionalPrivilegesByIdDTO) => {
|
||||||
const { scopeData, selector } = dto;
|
const { scopeData, selector } = dto;
|
||||||
const factory = scopeFactory[scopeData.scope];
|
const factory = scopeFactory[scopeData.scope];
|
||||||
const { membershipId } = await factory.onListAdditionalPrivilegesGuard(dto);
|
const { membershipId } = await factory.onGetAdditionalPrivilegesByIdGuard(dto);
|
||||||
const additionalPrivilege = await additionalPrivilegeDAL.findOne({
|
const additionalPrivilege = await additionalPrivilegeDAL.findOne({
|
||||||
id: selector.id,
|
id: selector.id,
|
||||||
membershipId
|
membershipId
|
||||||
@@ -182,6 +187,22 @@ export const additionalPrivilegeServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAdditionalPrivilegeByName = async (dto: TGetAdditionalPrivilegesByNameDTO) => {
|
||||||
|
const { scopeData, selector } = dto;
|
||||||
|
const factory = scopeFactory[scopeData.scope];
|
||||||
|
const { membershipId } = await factory.onGetAdditionalPrivilegesByIdGuard(dto);
|
||||||
|
const additionalPrivilege = await additionalPrivilegeDAL.findOne({
|
||||||
|
name: selector.name,
|
||||||
|
membershipId
|
||||||
|
});
|
||||||
|
if (!additionalPrivilege)
|
||||||
|
throw new NotFoundError({ message: `Additional privilege with name ${selector.name} doesn't exist` });
|
||||||
|
|
||||||
|
return {
|
||||||
|
additionalPrivilege: { ...additionalPrivilege, permissions: unpackPermissions(additionalPrivilege.permissions) }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const listAdditionalPrivileges = async (dto: TListAdditionalPrivilegesDTO) => {
|
const listAdditionalPrivileges = async (dto: TListAdditionalPrivilegesDTO) => {
|
||||||
const { scopeData } = dto;
|
const { scopeData } = dto;
|
||||||
const factory = scopeFactory[scopeData.scope];
|
const factory = scopeFactory[scopeData.scope];
|
||||||
@@ -203,6 +224,7 @@ export const additionalPrivilegeServiceFactory = ({
|
|||||||
updateAdditionalPrivilege,
|
updateAdditionalPrivilege,
|
||||||
deleteAdditionalPrivilege,
|
deleteAdditionalPrivilege,
|
||||||
getAdditionalPrivilegeById,
|
getAdditionalPrivilegeById,
|
||||||
|
getAdditionalPrivilegeByName,
|
||||||
listAdditionalPrivileges
|
listAdditionalPrivileges
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ export interface TAdditionalPrivilegesScopeFactory {
|
|||||||
onUpdateAdditionalPrivilegesGuard: (arg: TUpdateAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
onUpdateAdditionalPrivilegesGuard: (arg: TUpdateAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
||||||
onDeleteAdditionalPrivilegesGuard: (arg: TDeleteAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
onDeleteAdditionalPrivilegesGuard: (arg: TDeleteAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
||||||
onListAdditionalPrivilegesGuard: (arg: TListAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
onListAdditionalPrivilegesGuard: (arg: TListAdditionalPrivilegesDTO) => Promise<{ membershipId: string }>;
|
||||||
onGetAdditionalPrivilegesByIdGuard: (arg: TGetAdditionalPrivilegesByIdDTO) => Promise<{ membershipId: string }>;
|
onGetAdditionalPrivilegesByIdGuard: (
|
||||||
|
arg: TGetAdditionalPrivilegesByIdDTO | TGetAdditionalPrivilegesByNameDTO
|
||||||
|
) => Promise<{ membershipId: string }>;
|
||||||
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,3 +73,13 @@ export type TGetAdditionalPrivilegesByIdDTO = {
|
|||||||
actorType: MembershipActors;
|
actorType: MembershipActors;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TGetAdditionalPrivilegesByNameDTO = {
|
||||||
|
permission: OrgServiceActor;
|
||||||
|
scopeData: AccessScopeData;
|
||||||
|
selector: {
|
||||||
|
name: string;
|
||||||
|
actorId: string;
|
||||||
|
actorType: MembershipActors;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,88 +1,118 @@
|
|||||||
|
import { AccessScope } from "@app/db/schemas";
|
||||||
import { NotFoundError } from "@app/lib/errors";
|
import { NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TMembershipDALFactory } from "../membership/membership-dal";
|
import { TMembershipDALFactory } from "../membership/membership-dal";
|
||||||
import { TProjectDALFactory } from "../project/project-dal";
|
import { TProjectDALFactory } from "../project/project-dal";
|
||||||
import { AccessScope, AccessScopeData } from "@app/db/schemas";
|
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
|
||||||
|
|
||||||
type TConvertorServiceFactoryDep = {
|
type TConvertorServiceFactoryDep = {
|
||||||
projectDAL: Pick<TProjectDALFactory, "findOne">;
|
projectDAL: Pick<TProjectDALFactory, "findOne">;
|
||||||
membershipDAL: Pick<TMembershipDALFactory, "findOne">;
|
membershipDAL: Pick<TMembershipDALFactory, "findOne">;
|
||||||
|
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "getMembershipById" | "findOne">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TConvertorServiceFactory = ReturnType<typeof convertorServiceFactory>;
|
export type TConvertorServiceFactory = ReturnType<typeof convertorServiceFactory>;
|
||||||
|
|
||||||
export const convertorServiceFactory = ({ projectDAL, membershipDAL }: TConvertorServiceFactoryDep) => {
|
export const convertorServiceFactory = ({
|
||||||
const $getScopeDatabaseFields = (scopeData: AccessScopeData) => {
|
projectDAL,
|
||||||
if (scopeData.scope === AccessScope.Organization) {
|
membershipDAL,
|
||||||
return { scopeOrgId: scopeData.orgId };
|
additionalPrivilegeDAL
|
||||||
}
|
}: TConvertorServiceFactoryDep) => {
|
||||||
|
|
||||||
if (scopeData.scope === AccessScope.Namespace) {
|
|
||||||
return { scopeNamespaceId: scopeData.namespaceId, scopeOrgId: scopeData.orgId };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { scopeProjectId: scopeData.projectId, scopeOrgId: scopeData.orgId };
|
|
||||||
};
|
|
||||||
|
|
||||||
const projectSlugToId = async (dto: { slug: string; orgId: string }) => {
|
const projectSlugToId = async (dto: { slug: string; orgId: string }) => {
|
||||||
const project = await projectDAL.findOne({
|
const project = await projectDAL.findOne({
|
||||||
orgId: dto.orgId,
|
orgId: dto.orgId,
|
||||||
slug: dto.slug
|
slug: dto.slug
|
||||||
});
|
});
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug ${slug} not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug ${dto.slug} not found` });
|
||||||
return project;
|
return project;
|
||||||
};
|
};
|
||||||
|
|
||||||
const userMembershipIdToUserId = async (scopeData: AccessScopeData, membershipId: string) => {
|
const userMembershipIdToUserId = async (membershipId: string, scope: AccessScope, orgId: string) => {
|
||||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
|
||||||
|
|
||||||
const membership = await membershipDAL.findOne({
|
const membership = await membershipDAL.findOne({
|
||||||
scope: scopeData.scope,
|
scope,
|
||||||
id: membershipId,
|
id: membershipId,
|
||||||
...dbFields,
|
scopeOrgId: orgId
|
||||||
scopeOrgId: scopeData.orgId
|
|
||||||
});
|
});
|
||||||
if (!membership || !membership.actorUserId) {
|
if (!membership || !membership.actorUserId) {
|
||||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||||
}
|
}
|
||||||
return membership.actorUserId;
|
return { userId: membership.actorUserId, membership };
|
||||||
};
|
};
|
||||||
|
|
||||||
const groupMembershipIdToGroupId = async (scopeData: AccessScopeData, membershipId: string) => {
|
const groupMembershipIdToGroupId = async (membershipId: string, scope: AccessScope, orgId: string) => {
|
||||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
|
||||||
|
|
||||||
const membership = await membershipDAL.findOne({
|
const membership = await membershipDAL.findOne({
|
||||||
scope: scopeData.scope,
|
scope,
|
||||||
id: membershipId,
|
id: membershipId,
|
||||||
...dbFields,
|
scopeOrgId: orgId
|
||||||
scopeOrgId: scopeData.orgId
|
|
||||||
});
|
});
|
||||||
if (!membership || !membership.actorGroupId) {
|
if (!membership || !membership.actorGroupId) {
|
||||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
return membership.actorGroupId;
|
return { groupId: membership.actorGroupId, membership };
|
||||||
};
|
};
|
||||||
|
|
||||||
const identityMembershipIdToGroupId = async (scopeData: AccessScopeData, membershipId: string) => {
|
const identityMembershipIdToIdentityId = async (membershipId: string, scope: AccessScope, orgId: string) => {
|
||||||
const dbFields = $getScopeDatabaseFields(scopeData);
|
|
||||||
|
|
||||||
const membership = await membershipDAL.findOne({
|
const membership = await membershipDAL.findOne({
|
||||||
scope: scopeData.scope,
|
scope,
|
||||||
id: membershipId,
|
id: membershipId,
|
||||||
...dbFields,
|
scopeOrgId: orgId
|
||||||
scopeOrgId: scopeData.orgId
|
|
||||||
});
|
});
|
||||||
if (!membership || !membership.actorIdentityId) {
|
if (!membership || !membership.actorIdentityId) {
|
||||||
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
throw new NotFoundError({ message: `Membership with id ${membershipId} not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
return membership.actorIdentityId;
|
return { identityId: membership.actorIdentityId, membership };
|
||||||
|
};
|
||||||
|
|
||||||
|
const identityIdToMembershipId = async (identityId: string, scope: AccessScope, scopeId: string) => {
|
||||||
|
let fieldName = "scopeOrgId";
|
||||||
|
if (scope === AccessScope.Project) {
|
||||||
|
fieldName = "scopeProjectId";
|
||||||
|
} else if (scope === AccessScope.Namespace) {
|
||||||
|
fieldName = "scopeNamespaceId";
|
||||||
|
}
|
||||||
|
|
||||||
|
const membership = await membershipDAL.findOne({
|
||||||
|
scope,
|
||||||
|
actorIdentityId: identityId,
|
||||||
|
[fieldName]: scopeId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership) {
|
||||||
|
throw new NotFoundError({ message: `Identity with id ${identityId} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { membershipId: membership.id, membership };
|
||||||
|
};
|
||||||
|
|
||||||
|
const additionalPrivilegeIdToMembershipId = async (privilegeId: string, scope: AccessScope, orgId: string) => {
|
||||||
|
const membership = await additionalPrivilegeDAL.getMembershipById(privilegeId);
|
||||||
|
if (!membership || membership.scope !== scope || membership.scopeOrgId !== orgId) {
|
||||||
|
throw new NotFoundError({ message: `Privilege with id ${privilegeId} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { membership, membershipId: membership.id };
|
||||||
|
};
|
||||||
|
const additionalPrivilegeNameToId = async (privilegeName: string, membershipId: string) => {
|
||||||
|
const privilege = await additionalPrivilegeDAL.findOne({
|
||||||
|
name: privilegeName,
|
||||||
|
membershipId
|
||||||
|
});
|
||||||
|
if (!privilege) {
|
||||||
|
throw new NotFoundError({ message: `Privilege with slug ${privilegeName} not found` });
|
||||||
|
}
|
||||||
|
|
||||||
|
return { privilegeId: privilege.id, privilege };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
projectSlugToId,
|
projectSlugToId,
|
||||||
userMembershipIdToUserId,
|
userMembershipIdToUserId,
|
||||||
groupMembershipIdToGroupId,
|
groupMembershipIdToGroupId,
|
||||||
identityMembershipIdToGroupId
|
identityMembershipIdToIdentityId,
|
||||||
|
additionalPrivilegeIdToMembershipId,
|
||||||
|
additionalPrivilegeNameToId,
|
||||||
|
identityIdToMembershipId
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ export const membershipUserServiceFactory = ({
|
|||||||
const existingMembership = await membershipUserDAL.findOne({
|
const existingMembership = await membershipUserDAL.findOne({
|
||||||
scope: scopeData.scope,
|
scope: scopeData.scope,
|
||||||
...scopeDatabaseFields,
|
...scopeDatabaseFields,
|
||||||
actorUserId: dto.selector.actorId
|
actorUserId: dto.selector.userId
|
||||||
});
|
});
|
||||||
if (!existingMembership)
|
if (!existingMembership)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -338,31 +338,31 @@ export const membershipUserServiceFactory = ({
|
|||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
await membershipRoleDAL.insertMany(roleDocs, tx);
|
const insertedRoles = await membershipRoleDAL.insertMany(roleDocs, tx);
|
||||||
return doc;
|
return { ...doc, roles: insertedRoles };
|
||||||
});
|
});
|
||||||
|
|
||||||
return { memberships: membershipDoc };
|
return { membership: membershipDoc };
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteMembership = async (dto: TDeleteMembershipUserDTO) => {
|
const deleteMembership = async (dto: TDeleteMembershipUserDTO) => {
|
||||||
const { scopeData } = dto;
|
const { scopeData } = dto;
|
||||||
const factory = scopeFactory[scopeData.scope];
|
const factory = scopeFactory[scopeData.scope];
|
||||||
|
|
||||||
const { actorIdOfDeletor } = await factory.onDeleteMembershipUserGuard(dto);
|
await factory.onDeleteMembershipUserGuard(dto);
|
||||||
|
|
||||||
const scopeDatabaseFields = factory.getScopeDatabaseFields(dto.scopeData);
|
const scopeDatabaseFields = factory.getScopeDatabaseFields(dto.scopeData);
|
||||||
const existingMembership = await membershipUserDAL.findOne({
|
const existingMembership = await membershipUserDAL.findOne({
|
||||||
scope: scopeData.scope,
|
scope: scopeData.scope,
|
||||||
...scopeDatabaseFields,
|
...scopeDatabaseFields,
|
||||||
actorUserId: dto.selector.actorId
|
actorUserId: dto.selector.userId
|
||||||
});
|
});
|
||||||
if (!existingMembership)
|
if (!existingMembership)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "User doesn't have membership"
|
message: "User doesn't have membership"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingMembership.actorUserId === actorIdOfDeletor)
|
if (existingMembership.actorUserId === dto.permission.id)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "You can delete you own membership"
|
message: "You can delete you own membership"
|
||||||
});
|
});
|
||||||
@@ -403,7 +403,7 @@ export const membershipUserServiceFactory = ({
|
|||||||
await factory.onGetMembershipUserByUserIdGuard(dto);
|
await factory.onGetMembershipUserByUserIdGuard(dto);
|
||||||
const membership = await membershipUserDAL.getUserById({
|
const membership = await membershipUserDAL.getUserById({
|
||||||
scopeData,
|
scopeData,
|
||||||
userId: selector.actorId
|
userId: selector.userId
|
||||||
});
|
});
|
||||||
if (!membership) throw new NotFoundError({ message: `User membership not found` });
|
if (!membership) throw new NotFoundError({ message: `User membership not found` });
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export interface TMembershipUserScopeFactory {
|
|||||||
onCreateMembershipComplete: (arg: { id: string; email: string }[]) => Promise<void>;
|
onCreateMembershipComplete: (arg: { id: string; email: string }[]) => Promise<void>;
|
||||||
|
|
||||||
onUpdateMembershipUserGuard: (arg: TUpdateMembershipUserDTO) => Promise<void>;
|
onUpdateMembershipUserGuard: (arg: TUpdateMembershipUserDTO) => Promise<void>;
|
||||||
onDeleteMembershipUserGuard: (arg: TDeleteMembershipUserDTO) => Promise<{ actorIdOfDeletor: string }>;
|
onDeleteMembershipUserGuard: (arg: TDeleteMembershipUserDTO) => Promise<void>;
|
||||||
onListMembershipUserGuard: (arg: TListMembershipUserDTO) => Promise<void>;
|
onListMembershipUserGuard: (arg: TListMembershipUserDTO) => Promise<void>;
|
||||||
onGetMembershipUserByUserIdGuard: (arg: TGetMembershipUserByUserIdDTO) => Promise<void>;
|
onGetMembershipUserByUserIdGuard: (arg: TGetMembershipUserByUserIdDTO) => Promise<void>;
|
||||||
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
||||||
@@ -37,7 +37,7 @@ export type TUpdateMembershipUserDTO = {
|
|||||||
permission: OrgServiceActor;
|
permission: OrgServiceActor;
|
||||||
scopeData: AccessScopeData;
|
scopeData: AccessScopeData;
|
||||||
selector: {
|
selector: {
|
||||||
actorId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
data: {
|
data: {
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
@@ -67,7 +67,7 @@ export type TDeleteMembershipUserDTO = {
|
|||||||
permission: OrgServiceActor;
|
permission: OrgServiceActor;
|
||||||
scopeData: AccessScopeData;
|
scopeData: AccessScopeData;
|
||||||
selector: {
|
selector: {
|
||||||
actorId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,6 +75,6 @@ export type TGetMembershipUserByUserIdDTO = {
|
|||||||
permission: OrgServiceActor;
|
permission: OrgServiceActor;
|
||||||
scopeData: AccessScopeData;
|
scopeData: AccessScopeData;
|
||||||
selector: {
|
selector: {
|
||||||
actorId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,4 +63,4 @@ export const newNamespaceMembershipUserFactory = (
|
|||||||
getScopeDatabaseFields,
|
getScopeDatabaseFields,
|
||||||
isCustomRole
|
isCustomRole
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
dto.permission.orgId
|
dto.permission.orgId
|
||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
|
||||||
return { actorIdOfDeletor: dto.permission.id };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ export const newProjectMembershipUserFactory = ({
|
|||||||
actorOrgId: dto.permission.orgId
|
actorOrgId: dto.permission.orgId
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Delete, ProjectPermissionSub.Member);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Delete, ProjectPermissionSub.Member);
|
||||||
return { actorIdOfDeletor: dto.permission.id };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user