mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 21:29:20 +00:00
feat: fetch specific user group memberships
This commit is contained in:
@@ -464,6 +464,7 @@ export const registerRoutes = async (
|
|||||||
userAliasDAL,
|
userAliasDAL,
|
||||||
orgMembershipDAL,
|
orgMembershipDAL,
|
||||||
tokenService,
|
tokenService,
|
||||||
|
groupProjectDAL,
|
||||||
smtpService,
|
smtpService,
|
||||||
projectMembershipDAL
|
projectMembershipDAL
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
import { ProjectsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
@@ -134,4 +134,53 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/me/:username/groups",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
username: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
slug: z.string(),
|
||||||
|
orgId: z.string(),
|
||||||
|
projectMemberships: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string(),
|
||||||
|
project: ProjectsSchema.pick({ id: true, name: true, slug: true }),
|
||||||
|
roles: z.array(
|
||||||
|
z.object({
|
||||||
|
id: z.string(),
|
||||||
|
role: z.string(),
|
||||||
|
customRoleId: z.string().nullable(),
|
||||||
|
customRoleName: z.string().nullable(),
|
||||||
|
customRoleSlug: z.string().nullable(),
|
||||||
|
temporaryRange: z.string().nullable(),
|
||||||
|
temporaryMode: z.string().nullable(),
|
||||||
|
temporaryAccessEndTime: z.string().nullable(),
|
||||||
|
temporaryAccessStartTime: z.string().nullable(),
|
||||||
|
isTemporary: z.boolean()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const groupMemberships = await server.services.user.listUserGroups(req.params.username, req.permission.orgId);
|
||||||
|
|
||||||
|
return groupMemberships;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,6 +95,116 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findByUserId = async (userId: string, orgId: string, tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const docs = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
||||||
|
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
||||||
|
.join(TableName.Groups, function () {
|
||||||
|
this.on(`${TableName.UserGroupMembership}.groupId`, "=", `${TableName.Groups}.id`).andOn(
|
||||||
|
`${TableName.Groups}.orgId`,
|
||||||
|
"=",
|
||||||
|
db.raw("?", [orgId])
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.leftJoin(
|
||||||
|
TableName.GroupProjectMembership,
|
||||||
|
`${TableName.GroupProjectMembership}.groupId`,
|
||||||
|
`${TableName.Groups}.id`
|
||||||
|
)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.GroupProjectMembershipRole,
|
||||||
|
`${TableName.GroupProjectMembershipRole}.projectMembershipId`,
|
||||||
|
`${TableName.GroupProjectMembership}.id`
|
||||||
|
)
|
||||||
|
.leftJoin(
|
||||||
|
TableName.ProjectRoles,
|
||||||
|
`${TableName.GroupProjectMembershipRole}.customRoleId`,
|
||||||
|
`${TableName.ProjectRoles}.id`
|
||||||
|
)
|
||||||
|
.leftJoin(TableName.Project, `${TableName.GroupProjectMembership}.projectId`, `${TableName.Project}.id`)
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.Groups).as("groupId"),
|
||||||
|
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
||||||
|
db.ref("slug").withSchema(TableName.Groups).as("groupSlug"),
|
||||||
|
db.ref("orgId").withSchema(TableName.Groups),
|
||||||
|
db.ref("id").withSchema(TableName.GroupProjectMembership).as("projectMembershipId"),
|
||||||
|
db.ref("id").withSchema(TableName.Project).as("projectId"),
|
||||||
|
db.ref("name").withSchema(TableName.Project).as("projectName"),
|
||||||
|
db.ref("slug").withSchema(TableName.Project).as("projectSlug"),
|
||||||
|
db.ref("role").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("id").withSchema(TableName.GroupProjectMembershipRole).as("membershipRoleId"),
|
||||||
|
db.ref("customRoleId").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
||||||
|
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
||||||
|
db.ref("temporaryMode").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("isTemporary").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("temporaryRange").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("temporaryAccessStartTime").withSchema(TableName.GroupProjectMembershipRole),
|
||||||
|
db.ref("temporaryAccessEndTime").withSchema(TableName.GroupProjectMembershipRole)
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupsWithProjects = sqlNestRelationships({
|
||||||
|
data: docs,
|
||||||
|
parentMapper: ({ groupId, groupName, groupSlug, orgId: organizationId }) => ({
|
||||||
|
id: groupId,
|
||||||
|
name: groupName,
|
||||||
|
slug: groupSlug,
|
||||||
|
orgId: organizationId,
|
||||||
|
projectMemberships: []
|
||||||
|
}),
|
||||||
|
key: "groupId",
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
label: "projectMemberships" as const,
|
||||||
|
key: "projectMembershipId",
|
||||||
|
mapper: ({ projectId, projectName, projectSlug, projectMembershipId }) => ({
|
||||||
|
id: projectMembershipId,
|
||||||
|
project: {
|
||||||
|
id: projectId,
|
||||||
|
name: projectName,
|
||||||
|
slug: projectSlug
|
||||||
|
},
|
||||||
|
roles: []
|
||||||
|
}),
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
label: "roles" as const,
|
||||||
|
key: "membershipRoleId",
|
||||||
|
mapper: ({
|
||||||
|
role,
|
||||||
|
customRoleId,
|
||||||
|
customRoleName,
|
||||||
|
customRoleSlug,
|
||||||
|
membershipRoleId,
|
||||||
|
temporaryRange,
|
||||||
|
temporaryMode,
|
||||||
|
temporaryAccessEndTime,
|
||||||
|
temporaryAccessStartTime,
|
||||||
|
isTemporary
|
||||||
|
}) => ({
|
||||||
|
id: membershipRoleId,
|
||||||
|
role,
|
||||||
|
customRoleId,
|
||||||
|
customRoleName,
|
||||||
|
customRoleSlug,
|
||||||
|
temporaryRange,
|
||||||
|
temporaryMode,
|
||||||
|
temporaryAccessEndTime,
|
||||||
|
temporaryAccessStartTime,
|
||||||
|
isTemporary
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return groupsWithProjects;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "FindByUserId" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// The GroupProjectMembership table has a reference to the project (projectId) AND the group (groupId).
|
// The GroupProjectMembership table has a reference to the project (projectId) AND the group (groupId).
|
||||||
// We need to join the GroupProjectMembership table with the Groups table to get the group name and slug.
|
// We need to join the GroupProjectMembership table with the Groups table to get the group name and slug.
|
||||||
// We also need to join the GroupProjectMembershipRole table to get the role of the group in the project.
|
// We also need to join the GroupProjectMembershipRole table to get the role of the group in the project.
|
||||||
@@ -197,5 +307,5 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
return members;
|
return members;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...groupProjectOrm, findByProjectId, findAllProjectGroupMembers };
|
return { ...groupProjectOrm, findByProjectId, findByUserId, findAllProjectGroupMembers };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
|||||||
import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal";
|
import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal";
|
||||||
|
|
||||||
import { AuthMethod } from "../auth/auth-type";
|
import { AuthMethod } from "../auth/auth-type";
|
||||||
|
import { TGroupProjectDALFactory } from "../group-project/group-project-dal";
|
||||||
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal";
|
||||||
import { TUserDALFactory } from "./user-dal";
|
import { TUserDALFactory } from "./user-dal";
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ type TUserServiceFactoryDep = {
|
|||||||
| "delete"
|
| "delete"
|
||||||
>;
|
>;
|
||||||
userAliasDAL: Pick<TUserAliasDALFactory, "find" | "insertMany">;
|
userAliasDAL: Pick<TUserAliasDALFactory, "find" | "insertMany">;
|
||||||
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "findByUserId">;
|
||||||
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "find" | "insertMany" | "findOne" | "updateById">;
|
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "find" | "insertMany" | "findOne" | "updateById">;
|
||||||
tokenService: Pick<TAuthTokenServiceFactory, "createTokenForUser" | "validateTokenForUser">;
|
tokenService: Pick<TAuthTokenServiceFactory, "createTokenForUser" | "validateTokenForUser">;
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
||||||
@@ -40,6 +42,7 @@ export const userServiceFactory = ({
|
|||||||
userAliasDAL,
|
userAliasDAL,
|
||||||
orgMembershipDAL,
|
orgMembershipDAL,
|
||||||
projectMembershipDAL,
|
projectMembershipDAL,
|
||||||
|
groupProjectDAL,
|
||||||
tokenService,
|
tokenService,
|
||||||
smtpService
|
smtpService
|
||||||
}: TUserServiceFactoryDep) => {
|
}: TUserServiceFactoryDep) => {
|
||||||
@@ -295,6 +298,16 @@ export const userServiceFactory = ({
|
|||||||
return updatedOrgMembership.projectFavorites;
|
return updatedOrgMembership.projectFavorites;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const listUserGroups = async (username: string, orgId: string) => {
|
||||||
|
const user = await userDAL.findOne({
|
||||||
|
username
|
||||||
|
});
|
||||||
|
|
||||||
|
const memberships = await groupProjectDAL.findByUserId(user.id, orgId);
|
||||||
|
|
||||||
|
return memberships;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sendEmailVerificationCode,
|
sendEmailVerificationCode,
|
||||||
verifyEmailVerificationCode,
|
verifyEmailVerificationCode,
|
||||||
@@ -304,6 +317,7 @@ export const userServiceFactory = ({
|
|||||||
deleteUser,
|
deleteUser,
|
||||||
getMe,
|
getMe,
|
||||||
createUserAction,
|
createUserAction,
|
||||||
|
listUserGroups,
|
||||||
getUserAction,
|
getUserAction,
|
||||||
unlockUser,
|
unlockUser,
|
||||||
getUserPrivateKey,
|
getUserPrivateKey,
|
||||||
|
|||||||
Reference in New Issue
Block a user