mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 04:26:11 +00:00
Add project permission cache
This commit is contained in:
@@ -44,7 +44,13 @@ type TGroupServiceFactoryDep = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser" | "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser" | "findById">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete" | "findLatestProjectKey" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete" | "findLatestProjectKey" | "insertMany">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRole">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
| "getOrgPermission"
|
||||||
|
| "getOrgPermissionByRole"
|
||||||
|
| "invalidateUserProjectPermissionCache"
|
||||||
|
| "invalidateProjectPermissionCache"
|
||||||
|
>;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
oidcConfigDAL: Pick<TOidcConfigDALFactory, "findOne">;
|
oidcConfigDAL: Pick<TOidcConfigDALFactory, "findOne">;
|
||||||
};
|
};
|
||||||
@@ -225,6 +231,17 @@ export const groupServiceFactory = ({
|
|||||||
return updated;
|
return updated;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
const groupMembers = await userGroupMembershipDAL.find({ groupId: group.id });
|
||||||
|
const groupProjects = await groupProjectDAL.find({ groupId: group.id });
|
||||||
|
await Promise.allSettled([
|
||||||
|
...groupMembers.map((member) => permissionService.invalidateUserProjectPermissionCache(member.userId)),
|
||||||
|
...groupProjects.map((groupProject) =>
|
||||||
|
permissionService.invalidateProjectPermissionCache(groupProject.projectId)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return updatedGroup;
|
return updatedGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -247,11 +264,19 @@ export const groupServiceFactory = ({
|
|||||||
message: "Failed to delete group due to plan restriction. Upgrade plan to delete group."
|
message: "Failed to delete group due to plan restriction. Upgrade plan to delete group."
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupMembers = await userGroupMembershipDAL.find({ groupId: id });
|
||||||
|
const groupProjects = await groupProjectDAL.find({ groupId: id });
|
||||||
|
|
||||||
const [group] = await groupDAL.delete({
|
const [group] = await groupDAL.delete({
|
||||||
id,
|
id,
|
||||||
orgId: actorOrgId
|
orgId: actorOrgId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
...groupMembers.map((member) => permissionService.invalidateUserProjectPermissionCache(member.userId)),
|
||||||
|
...groupProjects.map((groupProject) => permissionService.invalidateProjectPermissionCache(groupProject.projectId))
|
||||||
|
]);
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -398,6 +423,12 @@ export const groupServiceFactory = ({
|
|||||||
projectBotDAL
|
projectBotDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupProjects = await groupProjectDAL.find({ groupId: group.id });
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(user.id),
|
||||||
|
...groupProjects.map((groupProject) => permissionService.invalidateProjectPermissionCache(groupProject.projectId))
|
||||||
|
]);
|
||||||
|
|
||||||
return users[0];
|
return users[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -479,6 +510,12 @@ export const groupServiceFactory = ({
|
|||||||
projectKeyDAL
|
projectKeyDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupProjects = await groupProjectDAL.find({ groupId: group.id });
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(user.id),
|
||||||
|
...groupProjects.map((groupProject) => permissionService.invalidateProjectPermissionCache(groupProject.projectId))
|
||||||
|
]);
|
||||||
|
|
||||||
return users[0];
|
return users[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+33
-1
@@ -28,7 +28,10 @@ type TIdentityProjectAdditionalPrivilegeV2ServiceFactoryDep = {
|
|||||||
identityProjectAdditionalPrivilegeDAL: TIdentityProjectAdditionalPrivilegeV2DALFactory;
|
identityProjectAdditionalPrivilegeDAL: TIdentityProjectAdditionalPrivilegeV2DALFactory;
|
||||||
identityProjectDAL: Pick<TIdentityProjectDALFactory, "findOne" | "findById">;
|
identityProjectDAL: Pick<TIdentityProjectDALFactory, "findOne" | "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
"getProjectPermission" | "invalidateProjectPermissionCache" | "invalidateIdentityProjectPermissionCache"
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityProjectAdditionalPrivilegeV2ServiceFactory = ReturnType<
|
export type TIdentityProjectAdditionalPrivilegeV2ServiceFactory = ReturnType<
|
||||||
@@ -115,6 +118,11 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
|
|||||||
permissions: packedPermission
|
permissions: packedPermission
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityProjectMembership.identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -132,6 +140,12 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
|
|||||||
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
||||||
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityProjectMembership.identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -224,6 +238,12 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
|
|||||||
temporaryAccessStartTime: new Date(temporaryAccessStartTime || ""),
|
temporaryAccessStartTime: new Date(temporaryAccessStartTime || ""),
|
||||||
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityProjectMembership.identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -239,6 +259,12 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
|
|||||||
temporaryRange: null,
|
temporaryRange: null,
|
||||||
temporaryMode: null
|
temporaryMode: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityProjectMembership.identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -294,6 +320,12 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const deletedPrivilege = await identityProjectAdditionalPrivilegeDAL.deleteById(identityPrivilege.id);
|
const deletedPrivilege = await identityProjectAdditionalPrivilegeDAL.deleteById(identityPrivilege.id);
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityProjectMembership.identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...deletedPrivilege,
|
...deletedPrivilege,
|
||||||
permissions: unpackPermissions(deletedPrivilege.permissions)
|
permissions: unpackPermissions(deletedPrivilege.permissions)
|
||||||
|
|||||||
+34
-2
@@ -31,7 +31,10 @@ type TIdentityProjectAdditionalPrivilegeServiceFactoryDep = {
|
|||||||
identityProjectAdditionalPrivilegeDAL: TIdentityProjectAdditionalPrivilegeDALFactory;
|
identityProjectAdditionalPrivilegeDAL: TIdentityProjectAdditionalPrivilegeDALFactory;
|
||||||
identityProjectDAL: Pick<TIdentityProjectDALFactory, "findOne" | "findById">;
|
identityProjectDAL: Pick<TIdentityProjectDALFactory, "findOne" | "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
"getProjectPermission" | "invalidateProjectPermissionCache" | "invalidateIdentityProjectPermissionCache"
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityProjectAdditionalPrivilegeServiceFactory = ReturnType<
|
export type TIdentityProjectAdditionalPrivilegeServiceFactory = ReturnType<
|
||||||
@@ -129,6 +132,12 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
|
|||||||
slug,
|
slug,
|
||||||
permissions: packedPermission
|
permissions: packedPermission
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -146,6 +155,12 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
||||||
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -250,6 +265,12 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryAccessStartTime: new Date(temporaryAccessStartTime || ""),
|
temporaryAccessStartTime: new Date(temporaryAccessStartTime || ""),
|
||||||
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -265,6 +286,12 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryRange: null,
|
temporaryRange: null,
|
||||||
temporaryMode: null
|
temporaryMode: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -338,9 +365,14 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deletedPrivilege = await identityProjectAdditionalPrivilegeDAL.deleteById(identityPrivilege.id);
|
const deletedPrivilege = await identityProjectAdditionalPrivilegeDAL.deleteById(identityPrivilege.id);
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(identityProjectMembership.projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...deletedPrivilege,
|
...deletedPrivilege,
|
||||||
|
|
||||||
permissions: unpackPermissions(deletedPrivilege.permissions)
|
permissions: unpackPermissions(deletedPrivilege.permissions)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -283,4 +283,7 @@ export type TPermissionServiceFactory = {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
checkPermissions: ProjectPermissionSet;
|
checkPermissions: ProjectPermissionSet;
|
||||||
}) => Promise<boolean>;
|
}) => Promise<boolean>;
|
||||||
|
invalidateProjectPermissionCache: (projectId: string) => Promise<void>;
|
||||||
|
invalidateUserProjectPermissionCache: (userId: string) => Promise<void>;
|
||||||
|
invalidateIdentityProjectPermissionCache: (identityId: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
projectViewerPermission,
|
projectViewerPermission,
|
||||||
sshHostBootstrapPermissions
|
sshHostBootstrapPermissions
|
||||||
} from "@app/ee/services/permission/default-roles";
|
} from "@app/ee/services/permission/default-roles";
|
||||||
|
import { KeyStorePrefixes, KeyStoreTtls, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { objectify } from "@app/lib/fn";
|
import { objectify } from "@app/lib/fn";
|
||||||
@@ -49,6 +50,7 @@ type TPermissionServiceFactoryDep = {
|
|||||||
serviceTokenDAL: Pick<TServiceTokenDALFactory, "findById">;
|
serviceTokenDAL: Pick<TServiceTokenDALFactory, "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
permissionDAL: TPermissionDALFactory;
|
permissionDAL: TPermissionDALFactory;
|
||||||
|
keyStore: TKeyStoreFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const permissionServiceFactory = ({
|
export const permissionServiceFactory = ({
|
||||||
@@ -56,7 +58,8 @@ export const permissionServiceFactory = ({
|
|||||||
orgRoleDAL,
|
orgRoleDAL,
|
||||||
projectRoleDAL,
|
projectRoleDAL,
|
||||||
serviceTokenDAL,
|
serviceTokenDAL,
|
||||||
projectDAL
|
projectDAL,
|
||||||
|
keyStore
|
||||||
}: TPermissionServiceFactoryDep): TPermissionServiceFactory => {
|
}: TPermissionServiceFactoryDep): TPermissionServiceFactory => {
|
||||||
const buildOrgPermission = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
const buildOrgPermission = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
||||||
const rules = orgUserRoles
|
const rules = orgUserRoles
|
||||||
@@ -83,6 +86,21 @@ export const permissionServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const invalidateProjectPermissionCache = async (projectId: string) => {
|
||||||
|
const pattern = KeyStorePrefixes.ProjectPermissionPattern(projectId);
|
||||||
|
await keyStore.deleteItems({ pattern });
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidateUserProjectPermissionCache = async (userId: string) => {
|
||||||
|
const pattern = KeyStorePrefixes.UserProjectPermissionPattern(userId);
|
||||||
|
await keyStore.deleteItems({ pattern });
|
||||||
|
};
|
||||||
|
|
||||||
|
const invalidateIdentityProjectPermissionCache = async (identityId: string) => {
|
||||||
|
const pattern = KeyStorePrefixes.IdentityProjectPermissionPattern(identityId);
|
||||||
|
await keyStore.deleteItems({ pattern });
|
||||||
|
};
|
||||||
|
|
||||||
const buildProjectPermissionRules = (projectUserRoles: TBuildProjectPermissionDTO) => {
|
const buildProjectPermissionRules = (projectUserRoles: TBuildProjectPermissionDTO) => {
|
||||||
const rules = projectUserRoles
|
const rules = projectUserRoles
|
||||||
.map(({ role, permissions }) => {
|
.map(({ role, permissions }) => {
|
||||||
@@ -577,35 +595,90 @@ export const permissionServiceFactory = ({
|
|||||||
actorId = assumedPrivilegeDetailsCtx.actorId;
|
actorId = assumedPrivilegeDetailsCtx.actorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cacheKey = KeyStorePrefixes.ProjectPermission(
|
||||||
|
projectId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actionProjectType || ActionProjectType.Any
|
||||||
|
);
|
||||||
|
|
||||||
|
if (actor === ActorType.SERVICE) {
|
||||||
|
return getServiceTokenProjectPermission({
|
||||||
|
serviceTokenId: actorId,
|
||||||
|
projectId,
|
||||||
|
actorOrgId,
|
||||||
|
actionProjectType
|
||||||
|
}) as Promise<TProjectPermissionRT<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cachedData = await keyStore.getItem(cacheKey);
|
||||||
|
if (cachedData) {
|
||||||
|
const parsed = JSON.parse(cachedData) as {
|
||||||
|
rules: RawRuleOf<MongoAbility<ProjectPermissionSet>>[];
|
||||||
|
membership: {
|
||||||
|
roles?: Array<{ role: string; customRoleSlug?: string }>;
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Reconstruct the permission object from cached rules
|
||||||
|
const permission = createMongoAbility<ProjectPermissionSet>(parsed.rules, {
|
||||||
|
conditionsMatcher
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
permission,
|
||||||
|
membership: parsed.membership,
|
||||||
|
hasRole: (role: string) =>
|
||||||
|
parsed.membership.roles?.findIndex(
|
||||||
|
({ role: slug, customRoleSlug }) => role === slug || slug === customRoleSlug
|
||||||
|
) !== -1
|
||||||
|
} as TProjectPermissionRT<T>;
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
let result: TProjectPermissionRT<T>;
|
||||||
|
|
||||||
switch (actor) {
|
switch (actor) {
|
||||||
case ActorType.USER:
|
case ActorType.USER:
|
||||||
return getUserProjectPermission({
|
result = (await getUserProjectPermission({
|
||||||
userId: actorId,
|
userId: actorId,
|
||||||
projectId,
|
projectId,
|
||||||
authMethod: actorAuthMethod,
|
authMethod: actorAuthMethod,
|
||||||
userOrgId: actorOrgId,
|
userOrgId: actorOrgId,
|
||||||
actionProjectType
|
actionProjectType
|
||||||
}) as Promise<TProjectPermissionRT<T>>;
|
})) as TProjectPermissionRT<T>;
|
||||||
case ActorType.SERVICE:
|
break;
|
||||||
return getServiceTokenProjectPermission({
|
|
||||||
serviceTokenId: actorId,
|
|
||||||
projectId,
|
|
||||||
actorOrgId,
|
|
||||||
actionProjectType
|
|
||||||
}) as Promise<TProjectPermissionRT<T>>;
|
|
||||||
case ActorType.IDENTITY:
|
case ActorType.IDENTITY:
|
||||||
return getIdentityProjectPermission({
|
result = (await getIdentityProjectPermission({
|
||||||
identityId: actorId,
|
identityId: actorId,
|
||||||
projectId,
|
projectId,
|
||||||
identityOrgId: actorOrgId,
|
identityOrgId: actorOrgId,
|
||||||
actionProjectType
|
actionProjectType
|
||||||
}) as Promise<TProjectPermissionRT<T>>;
|
})) as TProjectPermissionRT<T>;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid actor provided",
|
message: "Invalid actor provided",
|
||||||
name: "Get project permission"
|
name: "Get project permission"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cacheData = {
|
||||||
|
rules: result.permission.rules,
|
||||||
|
membership: result.membership
|
||||||
|
};
|
||||||
|
|
||||||
|
await keyStore.setItemWithExpiry(
|
||||||
|
cacheKey,
|
||||||
|
KeyStoreTtls.ProjectPermissionCacheInSeconds,
|
||||||
|
JSON.stringify(cacheData)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermissionByRole: TPermissionServiceFactory["getProjectPermissionByRole"] = async (
|
const getProjectPermissionByRole: TPermissionServiceFactory["getProjectPermissionByRole"] = async (
|
||||||
@@ -668,6 +741,9 @@ export const permissionServiceFactory = ({
|
|||||||
getProjectPermissionByRole,
|
getProjectPermissionByRole,
|
||||||
buildOrgPermission,
|
buildOrgPermission,
|
||||||
buildProjectPermissionRules,
|
buildProjectPermissionRules,
|
||||||
checkGroupProjectPermission
|
checkGroupProjectPermission,
|
||||||
|
invalidateProjectPermissionCache,
|
||||||
|
invalidateUserProjectPermissionCache,
|
||||||
|
invalidateIdentityProjectPermissionCache
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
+33
-1
@@ -27,7 +27,10 @@ import {
|
|||||||
type TProjectUserAdditionalPrivilegeServiceFactoryDep = {
|
type TProjectUserAdditionalPrivilegeServiceFactoryDep = {
|
||||||
projectUserAdditionalPrivilegeDAL: TProjectUserAdditionalPrivilegeDALFactory;
|
projectUserAdditionalPrivilegeDAL: TProjectUserAdditionalPrivilegeDALFactory;
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findById" | "findOne">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findById" | "findOne">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
"getProjectPermission" | "invalidateUserProjectPermissionCache" | "invalidateProjectPermissionCache"
|
||||||
|
>;
|
||||||
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update">;
|
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update">;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -115,6 +118,12 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
slug,
|
slug,
|
||||||
permissions: packedPermission
|
permissions: packedPermission
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectMembership.projectId),
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(projectMembership.userId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -133,6 +142,12 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
temporaryAccessStartTime: new Date(dto.temporaryAccessStartTime),
|
||||||
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
temporaryAccessEndTime: new Date(new Date(dto.temporaryAccessStartTime).getTime() + relativeTempAllocatedTimeInMs)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectMembership.projectId),
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(projectMembership.userId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -230,6 +245,11 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
temporaryAccessEndTime: new Date(new Date(temporaryAccessStartTime || "").getTime() + ms(temporaryRange || ""))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectMembership.projectId),
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(projectMembership.userId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -245,6 +265,12 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
temporaryRange: null,
|
temporaryRange: null,
|
||||||
temporaryMode: null
|
temporaryMode: null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectMembership.projectId),
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(projectMembership.userId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...additionalPrivilege,
|
...additionalPrivilege,
|
||||||
permissions: unpackPermissions(additionalPrivilege.permissions)
|
permissions: unpackPermissions(additionalPrivilege.permissions)
|
||||||
@@ -291,6 +317,12 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
const deletedPrivilege = await projectUserAdditionalPrivilegeDAL.deleteById(userPrivilege.id);
|
const deletedPrivilege = await projectUserAdditionalPrivilegeDAL.deleteById(userPrivilege.id);
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectMembership.projectId),
|
||||||
|
permissionService.invalidateUserProjectPermissionCache(projectMembership.userId)
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...deletedPrivilege,
|
...deletedPrivilege,
|
||||||
permissions: unpackPermissions(deletedPrivilege.permissions)
|
permissions: unpackPermissions(deletedPrivilege.permissions)
|
||||||
|
|||||||
@@ -63,13 +63,22 @@ export const KeyStorePrefixes = {
|
|||||||
ActiveSSEConnectionsSet: (projectId: string, identityId: string) =>
|
ActiveSSEConnectionsSet: (projectId: string, identityId: string) =>
|
||||||
`sse-connections:${projectId}:${identityId}` as const,
|
`sse-connections:${projectId}:${identityId}` as const,
|
||||||
ActiveSSEConnections: (projectId: string, identityId: string, connectionId: string) =>
|
ActiveSSEConnections: (projectId: string, identityId: string, connectionId: string) =>
|
||||||
`sse-connections:${projectId}:${identityId}:${connectionId}` as const
|
`sse-connections:${projectId}:${identityId}:${connectionId}` as const,
|
||||||
|
|
||||||
|
ProjectPermission: (projectId: string, actorType: string, actorId: string, actionProjectType: string) =>
|
||||||
|
`project-permission:${projectId}:${actorType}:${actorId}:${actionProjectType}` as const,
|
||||||
|
ProjectPermissionPattern: (projectId: string) => `project-permission:${projectId}:*` as const,
|
||||||
|
UserProjectPermissionPattern: (userId: string) => `project-permission:*:USER:${userId}:*` as const,
|
||||||
|
IdentityProjectPermissionPattern: (identityId: string) => `project-permission:*:IDENTITY:${identityId}:*` as const,
|
||||||
|
GroupMemberProjectPermissionPattern: (projectId: string, groupId: string) =>
|
||||||
|
`group-member-project-permission:${projectId}:${groupId}:*` as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const KeyStoreTtls = {
|
export const KeyStoreTtls = {
|
||||||
SetSyncSecretIntegrationLastRunTimestampInSeconds: 60,
|
SetSyncSecretIntegrationLastRunTimestampInSeconds: 60,
|
||||||
SetSecretSyncLastRunTimestampInSeconds: 60,
|
SetSecretSyncLastRunTimestampInSeconds: 60,
|
||||||
AccessTokenStatusUpdateInSeconds: 120
|
AccessTokenStatusUpdateInSeconds: 120,
|
||||||
|
ProjectPermissionCacheInSeconds: 300 // 5 minutes
|
||||||
};
|
};
|
||||||
|
|
||||||
type TDeleteItems = {
|
type TDeleteItems = {
|
||||||
|
|||||||
@@ -530,7 +530,8 @@ export const registerRoutes = async (
|
|||||||
orgRoleDAL,
|
orgRoleDAL,
|
||||||
projectRoleDAL,
|
projectRoleDAL,
|
||||||
serviceTokenDAL,
|
serviceTokenDAL,
|
||||||
projectDAL
|
projectDAL,
|
||||||
|
keyStore
|
||||||
});
|
});
|
||||||
const assumePrivilegeService = assumePrivilegeServiceFactory({
|
const assumePrivilegeService = assumePrivilegeServiceFactory({
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
|||||||
@@ -37,13 +37,19 @@ type TGroupProjectServiceFactoryDep = {
|
|||||||
TGroupProjectMembershipRoleDALFactory,
|
TGroupProjectMembershipRoleDALFactory,
|
||||||
"create" | "transaction" | "insertMany" | "delete"
|
"create" | "transaction" | "insertMany" | "delete"
|
||||||
>;
|
>;
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findGroupMembersNotInProject">;
|
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findGroupMembersNotInProject" | "find">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findOne" | "findProjectGhostUser" | "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findOne" | "findProjectGhostUser" | "findById">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany" | "transaction">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany" | "transaction">;
|
||||||
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
|
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
|
||||||
projectBotDAL: TProjectBotDALFactory;
|
projectBotDAL: TProjectBotDALFactory;
|
||||||
groupDAL: Pick<TGroupDALFactory, "findOne" | "findAllGroupPossibleMembers">;
|
groupDAL: Pick<TGroupDALFactory, "findOne" | "findAllGroupPossibleMembers">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
| "getProjectPermission"
|
||||||
|
| "getProjectPermissionByRole"
|
||||||
|
| "invalidateProjectPermissionCache"
|
||||||
|
| "invalidateUserProjectPermissionCache"
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TGroupProjectServiceFactory = ReturnType<typeof groupProjectServiceFactory>;
|
export type TGroupProjectServiceFactory = ReturnType<typeof groupProjectServiceFactory>;
|
||||||
@@ -263,6 +269,12 @@ export const groupProjectServiceFactory = ({
|
|||||||
return groupProjectMembership;
|
return groupProjectMembership;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupMembers = await userGroupMembershipDAL.find({ groupId: group.id });
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
...groupMembers.map((member) => permissionService.invalidateUserProjectPermissionCache(member.userId))
|
||||||
|
]);
|
||||||
|
|
||||||
return projectGroup;
|
return projectGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -372,6 +384,12 @@ export const groupProjectServiceFactory = ({
|
|||||||
return groupProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
return groupProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const groupMembers = await userGroupMembershipDAL.find({ groupId });
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
...groupMembers.map((member) => permissionService.invalidateUserProjectPermissionCache(member.userId))
|
||||||
|
]);
|
||||||
|
|
||||||
return updatedRoles;
|
return updatedRoles;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -403,15 +421,21 @@ export const groupProjectServiceFactory = ({
|
|||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Delete, ProjectPermissionSub.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionGroupActions.Delete, ProjectPermissionSub.Groups);
|
||||||
|
|
||||||
const deletedProjectGroup = await groupProjectDAL.transaction(async (tx) => {
|
const groupMembers = await userGroupMembershipDAL.find({ groupId: group.id });
|
||||||
const groupMembers = await userGroupMembershipDAL.findGroupMembersNotInProject(group.id, project.id, tx);
|
|
||||||
|
|
||||||
if (groupMembers.length) {
|
const deletedProjectGroup = await groupProjectDAL.transaction(async (tx) => {
|
||||||
|
const groupMembersNotInProject = await userGroupMembershipDAL.findGroupMembersNotInProject(
|
||||||
|
group.id,
|
||||||
|
project.id,
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
if (groupMembersNotInProject.length) {
|
||||||
await projectKeyDAL.delete(
|
await projectKeyDAL.delete(
|
||||||
{
|
{
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
$in: {
|
$in: {
|
||||||
receiverId: groupMembers.map(({ user: { id } }) => id)
|
receiverId: groupMembersNotInProject.map(({ user: { id } }) => id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
@@ -422,6 +446,11 @@ export const groupProjectServiceFactory = ({
|
|||||||
return projectGroup;
|
return projectGroup;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
...groupMembers.map((member) => permissionService.invalidateUserProjectPermissionCache(member.userId))
|
||||||
|
]);
|
||||||
|
|
||||||
return deletedProjectGroup;
|
return deletedProjectGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,13 @@ type TIdentityProjectServiceFactoryDep = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
|
projectRoleDAL: Pick<TProjectRoleDALFactory, "find">;
|
||||||
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
| "getProjectPermission"
|
||||||
|
| "getProjectPermissionByRole"
|
||||||
|
| "invalidateIdentityProjectPermissionCache"
|
||||||
|
| "invalidateProjectPermissionCache"
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityProjectServiceFactory = ReturnType<typeof identityProjectServiceFactory>;
|
export type TIdentityProjectServiceFactory = ReturnType<typeof identityProjectServiceFactory>;
|
||||||
@@ -165,6 +171,12 @@ export const identityProjectServiceFactory = ({
|
|||||||
const identityRoles = await identityProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
const identityRoles = await identityProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
||||||
return { ...identityProjectMembership, roles: identityRoles };
|
return { ...identityProjectMembership, roles: identityRoles };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return projectIdentity;
|
return projectIdentity;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -272,6 +284,11 @@ export const identityProjectServiceFactory = ({
|
|||||||
return identityProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
return identityProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return updatedRoles;
|
return updatedRoles;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,6 +319,12 @@ export const identityProjectServiceFactory = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [deletedIdentity] = await identityProjectDAL.delete({ identityId, projectId });
|
const [deletedIdentity] = await identityProjectDAL.delete({ identityId, projectId });
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
permissionService.invalidateIdentityProjectPermissionCache(identityId)
|
||||||
|
]);
|
||||||
|
|
||||||
return deletedIdentity;
|
return deletedIdentity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,13 @@ import {
|
|||||||
import { TProjectUserMembershipRoleDALFactory } from "./project-user-membership-role-dal";
|
import { TProjectUserMembershipRoleDALFactory } from "./project-user-membership-role-dal";
|
||||||
|
|
||||||
type TProjectMembershipServiceFactoryDep = {
|
type TProjectMembershipServiceFactoryDep = {
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRole">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
| "getProjectPermission"
|
||||||
|
| "getProjectPermissionByRole"
|
||||||
|
| "invalidateUserProjectPermissionCache"
|
||||||
|
| "invalidateProjectPermissionCache"
|
||||||
|
>;
|
||||||
smtpService: TSmtpService;
|
smtpService: TSmtpService;
|
||||||
projectBotDAL: TProjectBotDALFactory;
|
projectBotDAL: TProjectBotDALFactory;
|
||||||
projectMembershipDAL: TProjectMembershipDALFactory;
|
projectMembershipDAL: TProjectMembershipDALFactory;
|
||||||
@@ -239,6 +245,13 @@ export const projectMembershipServiceFactory = ({
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
...orgMembers.map(({ userId }) =>
|
||||||
|
userId ? permissionService.invalidateUserProjectPermissionCache(userId) : Promise.resolve()
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
if (sendEmails) {
|
if (sendEmails) {
|
||||||
await notificationService.createUserNotifications(
|
await notificationService.createUserNotifications(
|
||||||
orgMembers.map((member) => ({
|
orgMembers.map((member) => ({
|
||||||
@@ -371,6 +384,13 @@ export const projectMembershipServiceFactory = ({
|
|||||||
return projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
return projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
membershipUser?.userId
|
||||||
|
? permissionService.invalidateUserProjectPermissionCache(membershipUser.userId)
|
||||||
|
: Promise.resolve()
|
||||||
|
]);
|
||||||
|
|
||||||
return updatedRoles;
|
return updatedRoles;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -414,6 +434,12 @@ export const projectMembershipServiceFactory = ({
|
|||||||
);
|
);
|
||||||
return deletedMembership;
|
return deletedMembership;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
membership.userId ? permissionService.invalidateUserProjectPermissionCache(membership.userId) : Promise.resolve()
|
||||||
|
]);
|
||||||
|
|
||||||
return membership;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -515,6 +541,14 @@ export const projectMembershipServiceFactory = ({
|
|||||||
|
|
||||||
return deletedMemberships;
|
return deletedMemberships;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled([
|
||||||
|
permissionService.invalidateProjectPermissionCache(projectId),
|
||||||
|
...memberships.map(({ userId }) =>
|
||||||
|
userId ? permissionService.invalidateUserProjectPermissionCache(userId) : Promise.resolve()
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
return memberships;
|
return memberships;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ type TProjectRoleServiceFactoryDep = {
|
|||||||
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
userDAL: Pick<TUserDALFactory, "findById">;
|
userDAL: Pick<TUserDALFactory, "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findProjectById">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findProjectById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getUserProjectPermission">;
|
permissionService: Pick<
|
||||||
|
TPermissionServiceFactory,
|
||||||
|
"getProjectPermission" | "getUserProjectPermission" | "invalidateProjectPermissionCache"
|
||||||
|
>;
|
||||||
identityProjectMembershipRoleDAL: TIdentityProjectMembershipRoleDALFactory;
|
identityProjectMembershipRoleDAL: TIdentityProjectMembershipRoleDALFactory;
|
||||||
projectUserMembershipRoleDAL: TProjectUserMembershipRoleDALFactory;
|
projectUserMembershipRoleDAL: TProjectUserMembershipRoleDALFactory;
|
||||||
};
|
};
|
||||||
@@ -162,6 +165,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!updatedRole) throw new NotFoundError({ message: "Project role not found", name: "Update role" });
|
if (!updatedRole) throw new NotFoundError({ message: "Project role not found", name: "Update role" });
|
||||||
|
|
||||||
|
await permissionService.invalidateProjectPermissionCache(projectRole.projectId);
|
||||||
|
|
||||||
return { ...updatedRole, permissions: unpackPermissions(updatedRole.permissions) };
|
return { ...updatedRole, permissions: unpackPermissions(updatedRole.permissions) };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,6 +202,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
const deletedRole = await projectRoleDAL.deleteById(roleId);
|
const deletedRole = await projectRoleDAL.deleteById(roleId);
|
||||||
if (!deletedRole) throw new NotFoundError({ message: "Project role not found", name: "Delete role" });
|
if (!deletedRole) throw new NotFoundError({ message: "Project role not found", name: "Delete role" });
|
||||||
|
|
||||||
|
await permissionService.invalidateProjectPermissionCache(projectRole.projectId);
|
||||||
|
|
||||||
return { ...deletedRole, permissions: unpackPermissions(deletedRole.permissions) };
|
return { ...deletedRole, permissions: unpackPermissions(deletedRole.permissions) };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user