Skip to content

Commit

Permalink
Merge pull request #2431 from Infisical/misc/terraform-project-group-…
Browse files Browse the repository at this point in the history
…prereq

misc: setup prerequisites for terraform project group
  • Loading branch information
maidul98 authored Sep 23, 2024
2 parents fa64a88 + 839f0c7 commit 1dc0f4e
Show file tree
Hide file tree
Showing 24 changed files with 555 additions and 232 deletions.
90 changes: 69 additions & 21 deletions backend/src/ee/routes/v1/group-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
body: z.object({
name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name),
Expand Down Expand Up @@ -43,12 +43,59 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
});

server.route({
url: "/:currentSlug",
url: "/:id",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
id: z.string()
}),
response: {
200: GroupsSchema
}
},
handler: async (req) => {
const group = await server.services.group.getGroupById({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.id
});

return group;
}
});

server.route({
url: "/",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
response: {
200: GroupsSchema.array()
}
},
handler: async (req) => {
const groups = await server.services.org.getOrgGroups({
actor: req.permission.type,
actorId: req.permission.id,
orgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});

return groups;
}
});

server.route({
url: "/:id",
method: "PATCH",
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
currentSlug: z.string().trim().describe(GROUPS.UPDATE.currentSlug)
id: z.string().trim().describe(GROUPS.UPDATE.id)
}),
body: z
.object({
Expand All @@ -70,7 +117,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const group = await server.services.group.updateGroup({
currentSlug: req.params.currentSlug,
id: req.params.id,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
Expand All @@ -83,20 +130,20 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
});

server.route({
url: "/:slug",
url: "/:id",
method: "DELETE",
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
slug: z.string().trim().describe(GROUPS.DELETE.slug)
id: z.string().trim().describe(GROUPS.DELETE.id)
}),
response: {
200: GroupsSchema
}
},
handler: async (req) => {
const group = await server.services.group.deleteGroup({
groupSlug: req.params.slug,
id: req.params.id,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
Expand All @@ -109,11 +156,11 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {

server.route({
method: "GET",
url: "/:slug/users",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/:id/users",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
slug: z.string().trim().describe(GROUPS.LIST_USERS.slug)
id: z.string().trim().describe(GROUPS.LIST_USERS.id)
}),
querystring: z.object({
offset: z.coerce.number().min(0).max(100).default(0).describe(GROUPS.LIST_USERS.offset),
Expand Down Expand Up @@ -141,24 +188,25 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { users, totalCount } = await server.services.group.listGroupUsers({
groupSlug: req.params.slug,
id: req.params.id,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});

return { users, totalCount };
}
});

server.route({
method: "POST",
url: "/:slug/users/:username",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/:id/users/:username",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
slug: z.string().trim().describe(GROUPS.ADD_USER.slug),
id: z.string().trim().describe(GROUPS.ADD_USER.id),
username: z.string().trim().describe(GROUPS.ADD_USER.username)
}),
response: {
Expand All @@ -173,7 +221,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const user = await server.services.group.addUserToGroup({
groupSlug: req.params.slug,
id: req.params.id,
username: req.params.username,
actor: req.permission.type,
actorId: req.permission.id,
Expand All @@ -187,11 +235,11 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {

server.route({
method: "DELETE",
url: "/:slug/users/:username",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/:id/users/:username",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
slug: z.string().trim().describe(GROUPS.DELETE_USER.slug),
id: z.string().trim().describe(GROUPS.DELETE_USER.id),
username: z.string().trim().describe(GROUPS.DELETE_USER.username)
}),
response: {
Expand All @@ -206,7 +254,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const user = await server.services.group.removeUserFromGroup({
groupSlug: req.params.slug,
id: req.params.id,
username: req.params.username,
actor: req.permission.type,
actorId: req.permission.id,
Expand Down
74 changes: 47 additions & 27 deletions backend/src/ee/services/group/group-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import slugify from "@sindresorhus/slugify";

import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
Expand All @@ -21,6 +21,7 @@ import {
TAddUserToGroupDTO,
TCreateGroupDTO,
TDeleteGroupDTO,
TGetGroupByIdDTO,
TListGroupUsersDTO,
TRemoveUserFromGroupDTO,
TUpdateGroupDTO
Expand All @@ -29,7 +30,7 @@ import { TUserGroupMembershipDALFactory } from "./user-group-membership-dal";

type TGroupServiceFactoryDep = {
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUserIdsBatch" | "transaction" | "findOne">;
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "update" | "delete" | "findAllGroupMembers">;
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "update" | "delete" | "findAllGroupMembers" | "findById">;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
orgDAL: Pick<TOrgDALFactory, "findMembership" | "countAllOrgMembers">;
userGroupMembershipDAL: Pick<
Expand Down Expand Up @@ -95,7 +96,7 @@ export const groupServiceFactory = ({
};

const updateGroup = async ({
currentSlug,
id,
name,
slug,
role,
Expand All @@ -121,8 +122,10 @@ export const groupServiceFactory = ({
message: "Failed to update group due to plan restrictio Upgrade plan to update group."
});

const group = await groupDAL.findOne({ orgId: actorOrgId, slug: currentSlug });
if (!group) throw new BadRequestError({ message: `Failed to find group with slug ${currentSlug}` });
const group = await groupDAL.findOne({ orgId: actorOrgId, id });
if (!group) {
throw new BadRequestError({ message: `Failed to find group with ID ${id}` });
}

let customRole: TOrgRoles | undefined;
if (role) {
Expand All @@ -140,8 +143,7 @@ export const groupServiceFactory = ({

const [updatedGroup] = await groupDAL.update(
{
orgId: actorOrgId,
slug: currentSlug
id: group.id
},
{
name,
Expand All @@ -158,7 +160,7 @@ export const groupServiceFactory = ({
return updatedGroup;
};

const deleteGroup = async ({ groupSlug, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => {
const deleteGroup = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => {
if (!actorOrgId) throw new BadRequestError({ message: "Failed to create group without organization" });

const { permission } = await permissionService.getOrgPermission(
Expand All @@ -178,15 +180,39 @@ export const groupServiceFactory = ({
});

const [group] = await groupDAL.delete({
orgId: actorOrgId,
slug: groupSlug
id,
orgId: actorOrgId
});

return group;
};

const getGroupById = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TGetGroupByIdDTO) => {
if (!actorOrgId) {
throw new BadRequestError({ message: "Failed to read group without organization" });
}

const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Groups);

const group = await groupDAL.findById(id);
if (!group) {
throw new NotFoundError({
message: `Cannot find group with ID ${id}`
});
}

return group;
};

const listGroupUsers = async ({
groupSlug,
id,
offset,
limit,
username,
Expand All @@ -208,12 +234,12 @@ export const groupServiceFactory = ({

const group = await groupDAL.findOne({
orgId: actorOrgId,
slug: groupSlug
id
});

if (!group)
throw new BadRequestError({
message: `Failed to find group with slug ${groupSlug}`
message: `Failed to find group with ID ${id}`
});

const users = await groupDAL.findAllGroupMembers({
Expand All @@ -229,14 +255,7 @@ export const groupServiceFactory = ({
return { users, totalCount: count };
};

const addUserToGroup = async ({
groupSlug,
username,
actor,
actorId,
actorAuthMethod,
actorOrgId
}: TAddUserToGroupDTO) => {
const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => {
if (!actorOrgId) throw new BadRequestError({ message: "Failed to create group without organization" });

const { permission } = await permissionService.getOrgPermission(
Expand All @@ -251,12 +270,12 @@ export const groupServiceFactory = ({
// check if group with slug exists
const group = await groupDAL.findOne({
orgId: actorOrgId,
slug: groupSlug
id
});

if (!group)
throw new BadRequestError({
message: `Failed to find group with slug ${groupSlug}`
message: `Failed to find group with ID ${id}`
});

const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId);
Expand Down Expand Up @@ -285,7 +304,7 @@ export const groupServiceFactory = ({
};

const removeUserFromGroup = async ({
groupSlug,
id,
username,
actor,
actorId,
Expand All @@ -306,12 +325,12 @@ export const groupServiceFactory = ({
// check if group with slug exists
const group = await groupDAL.findOne({
orgId: actorOrgId,
slug: groupSlug
id
});

if (!group)
throw new BadRequestError({
message: `Failed to find group with slug ${groupSlug}`
message: `Failed to find group with ID ${id}`
});

const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId);
Expand Down Expand Up @@ -342,6 +361,7 @@ export const groupServiceFactory = ({
deleteGroup,
listGroupUsers,
addUserToGroup,
removeUserFromGroup
removeUserFromGroup,
getGroupById
};
};
Loading

0 comments on commit 1dc0f4e

Please sign in to comment.