mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 21:27:31 +00:00
feat(infisical-pg): added routes for workspaces and updated frontend
This commit is contained in:
Vendored
+10
@@ -10,6 +10,11 @@ import { AuthMode } from "@app/services/auth/auth-signup-type";
|
|||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
import { TOrgRoleServiceFactory } from "@app/services/org/org-role-service";
|
import { TOrgRoleServiceFactory } from "@app/services/org/org-role-service";
|
||||||
import { TOrgServiceFactory } from "@app/services/org/org-service";
|
import { TOrgServiceFactory } from "@app/services/org/org-service";
|
||||||
|
import { TProjectServiceFactory } from "@app/services/project/project-service";
|
||||||
|
import { TProjectEnvServiceFactory } from "@app/services/project-env/project-env-service";
|
||||||
|
import { TProjectKeyServiceFactory } from "@app/services/project-key/project-key-service";
|
||||||
|
import { TProjectMembershipServiceFactory } from "@app/services/project-membership/project-membership-service";
|
||||||
|
import { TProjectRoleServiceFactory } from "@app/services/project-role/project-role-service";
|
||||||
import { TSuperAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
import { TSuperAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
||||||
import { TAuthTokenServiceFactory } from "@app/services/token/token-service";
|
import { TAuthTokenServiceFactory } from "@app/services/token/token-service";
|
||||||
import { TUserDalFactory } from "@app/services/user/user-dal";
|
import { TUserDalFactory } from "@app/services/user/user-dal";
|
||||||
@@ -54,6 +59,11 @@ declare module "fastify" {
|
|||||||
superAdmin: TSuperAdminServiceFactory;
|
superAdmin: TSuperAdminServiceFactory;
|
||||||
user: TUserServiceFactory;
|
user: TUserServiceFactory;
|
||||||
apiKey: TApiKeyServiceFactory;
|
apiKey: TApiKeyServiceFactory;
|
||||||
|
project: TProjectServiceFactory;
|
||||||
|
projectMembership: TProjectMembershipServiceFactory;
|
||||||
|
projectEnv: TProjectEnvServiceFactory;
|
||||||
|
projectKey: TProjectKeyServiceFactory;
|
||||||
|
projectRole: TProjectRoleServiceFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { registerOrgRoleRouter } from "./org-role-router";
|
import { registerOrgRoleRouter } from "./org-role-router";
|
||||||
|
import { registerProjectRoleRouter } from "./project-role-router";
|
||||||
|
|
||||||
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
||||||
// org role starts with organization
|
// org role starts with organization
|
||||||
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
||||||
|
await server.register(registerProjectRoleRouter, { prefix: "/workspace" });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
slug: z.string().trim(),
|
slug: z.string().trim(),
|
||||||
name: z.string().trim(),
|
name: z.string().trim(),
|
||||||
description: z.string().trim().optional(),
|
description: z.string().trim().optional(),
|
||||||
workspaceId: z.string().trim().optional(),
|
|
||||||
permissions: z.any().array()
|
permissions: z.any().array()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
@@ -62,10 +61,7 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
req.auth.userId,
|
req.auth.userId,
|
||||||
req.params.organizationId,
|
req.params.organizationId,
|
||||||
req.params.roleId,
|
req.params.roleId,
|
||||||
{
|
req.body
|
||||||
...req.body,
|
|
||||||
permissions: req.body.permissions ? JSON.stringify(req.body.permissions) : undefined
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
return { role };
|
return { role };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { ProjectMembershipsSchema, ProjectRolesSchema } from "@app/db/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/:projectId/roles",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
slug: z.string().trim(),
|
||||||
|
name: z.string().trim(),
|
||||||
|
description: z.string().trim().optional(),
|
||||||
|
permissions: z.any().array()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
role: ProjectRolesSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const role = await server.services.projectRole.createRole(
|
||||||
|
req.permission.type,
|
||||||
|
req.permission.id,
|
||||||
|
req.params.projectId,
|
||||||
|
req.body
|
||||||
|
);
|
||||||
|
return { role };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:projectId/roles/:roleId",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim(),
|
||||||
|
roleId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
slug: z.string().trim().optional(),
|
||||||
|
name: z.string().trim().optional(),
|
||||||
|
description: z.string().trim().optional(),
|
||||||
|
permissions: z.any().array()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
role: ProjectRolesSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const role = await server.services.projectRole.updateRole(
|
||||||
|
req.permission.type,
|
||||||
|
req.permission.id,
|
||||||
|
req.params.projectId,
|
||||||
|
req.params.roleId,
|
||||||
|
req.body
|
||||||
|
);
|
||||||
|
return { role };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/:projectId/roles/:roleId",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim(),
|
||||||
|
roleId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
role: ProjectRolesSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const role = await server.services.projectRole.deleteRole(
|
||||||
|
req.permission.type,
|
||||||
|
req.permission.id,
|
||||||
|
req.params.projectId,
|
||||||
|
req.params.roleId
|
||||||
|
);
|
||||||
|
return { role };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/roles",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
data: z.object({
|
||||||
|
roles: ProjectRolesSchema.omit({ permissions: true })
|
||||||
|
.merge(z.object({ permissions: z.unknown() }))
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const roles = await server.services.projectRole.listRoles(
|
||||||
|
req.permission.type,
|
||||||
|
req.permission.id,
|
||||||
|
req.params.projectId
|
||||||
|
);
|
||||||
|
return { data: { roles } };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/:projectId/permissions",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
projectId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
membership: ProjectMembershipsSchema,
|
||||||
|
permissions: z.any().array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { permissions, membership } = await server.services.projectRole.getUserPermission(
|
||||||
|
req.auth.userId,
|
||||||
|
req.params.projectId
|
||||||
|
);
|
||||||
|
return { permissions, membership };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -16,7 +16,9 @@ import {
|
|||||||
projectAdminPermissions,
|
projectAdminPermissions,
|
||||||
projectMemberPermissions,
|
projectMemberPermissions,
|
||||||
projectNoAccessPermissions,
|
projectNoAccessPermissions,
|
||||||
projectViewerPermission} from "./project-permission";
|
ProjectPermissionSet,
|
||||||
|
projectViewerPermission
|
||||||
|
} from "./project-permission";
|
||||||
|
|
||||||
type TPermissionServiceFactoryDep = {
|
type TPermissionServiceFactoryDep = {
|
||||||
permissionDal: TPermissionDalFactory;
|
permissionDal: TPermissionDalFactory;
|
||||||
@@ -68,9 +70,9 @@ export const permissionServiceFactory = ({ permissionDal }: TPermissionServiceFa
|
|||||||
if (membership.role === ProjectMembershipRole.NoAccess)
|
if (membership.role === ProjectMembershipRole.NoAccess)
|
||||||
return { permission: projectNoAccessPermissions, membership };
|
return { permission: projectNoAccessPermissions, membership };
|
||||||
if (membership.role === ProjectMembershipRole.Custom) {
|
if (membership.role === ProjectMembershipRole.Custom) {
|
||||||
const permission = createMongoAbility<OrgPermissionSet>(
|
const permission = createMongoAbility<ProjectPermissionSet>(
|
||||||
// akhilmhdh: putting any due to ts incompatiable matching with string and the other
|
// akhilmhdh: putting any due to ts incompatiable matching with string and the other
|
||||||
unpackRules<RawRuleOf<MongoAbility<OrgPermissionSet>>>(membership.permissions as any),
|
unpackRules<RawRuleOf<MongoAbility<ProjectPermissionSet>>>(membership.permissions as any),
|
||||||
{
|
{
|
||||||
conditionsMatcher
|
conditionsMatcher
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ import { orgDalFactory } from "@app/services/org/org-dal";
|
|||||||
import { orgRoleDalFactory } from "@app/services/org/org-role-dal";
|
import { orgRoleDalFactory } from "@app/services/org/org-role-dal";
|
||||||
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
||||||
import { orgServiceFactory } from "@app/services/org/org-service";
|
import { orgServiceFactory } from "@app/services/org/org-service";
|
||||||
|
import { projectDalFactory } from "@app/services/project/project-dal";
|
||||||
|
import { projectServiceFactory } from "@app/services/project/project-service";
|
||||||
|
import { projectEnvDalFactory } from "@app/services/project-env/project-env-dal";
|
||||||
|
import { projectEnvServiceFactory } from "@app/services/project-env/project-env-service";
|
||||||
|
import { projectKeyDalFactory } from "@app/services/project-key/project-key-dal";
|
||||||
|
import { projectKeyServiceFactory } from "@app/services/project-key/project-key-service";
|
||||||
|
import { projectMembershipDalFactory } from "@app/services/project-membership/project-membership-dal";
|
||||||
|
import { projectMembershipServiceFactory } from "@app/services/project-membership/project-membership-service";
|
||||||
|
import { projectRoleDalFactory } from "@app/services/project-role/project-role-dal";
|
||||||
|
import { projectRoleServiceFactory } from "@app/services/project-role/project-role-service";
|
||||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
import { superAdminDalFactory } from "@app/services/super-admin/super-admin-dal";
|
import { superAdminDalFactory } from "@app/services/super-admin/super-admin-dal";
|
||||||
import { superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
import { superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
||||||
@@ -43,6 +53,12 @@ export const registerRoutes = async (
|
|||||||
const superAdminDal = superAdminDalFactory(db);
|
const superAdminDal = superAdminDalFactory(db);
|
||||||
const apiKeyDal = apiKeyDalFactory(db);
|
const apiKeyDal = apiKeyDalFactory(db);
|
||||||
|
|
||||||
|
const projectDal = projectDalFactory(db);
|
||||||
|
const projectMembershipDal = projectMembershipDalFactory(db);
|
||||||
|
const projectRoleDal = projectRoleDalFactory(db);
|
||||||
|
const projectEnvDal = projectEnvDalFactory(db);
|
||||||
|
const projectKeyDal = projectKeyDalFactory(db);
|
||||||
|
|
||||||
// ee db layer ops
|
// ee db layer ops
|
||||||
const permissionDal = permissionDalFactory(db);
|
const permissionDal = permissionDalFactory(db);
|
||||||
|
|
||||||
@@ -84,6 +100,30 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
const apiKeyService = apiKeyServiceFactory({ apiKeyDal });
|
const apiKeyService = apiKeyServiceFactory({ apiKeyDal });
|
||||||
|
|
||||||
|
const projectService = projectServiceFactory({
|
||||||
|
permissionService,
|
||||||
|
projectDal,
|
||||||
|
projectEnvDal,
|
||||||
|
projectMembershipDal
|
||||||
|
});
|
||||||
|
const projectMembershipService = projectMembershipServiceFactory({
|
||||||
|
projectMembershipDal,
|
||||||
|
projectDal,
|
||||||
|
permissionService,
|
||||||
|
orgDal,
|
||||||
|
userDal,
|
||||||
|
smtpService,
|
||||||
|
projectKeyDal,
|
||||||
|
projectRoleDal
|
||||||
|
});
|
||||||
|
const projectEnvService = projectEnvServiceFactory({ permissionService, projectEnvDal });
|
||||||
|
const projectKeyService = projectKeyServiceFactory({
|
||||||
|
permissionService,
|
||||||
|
projectKeyDal,
|
||||||
|
projectMembershipDal
|
||||||
|
});
|
||||||
|
const projectRoleService = projectRoleServiceFactory({ permissionService, projectRoleDal });
|
||||||
|
|
||||||
await superAdminService.initServerCfg();
|
await superAdminService.initServerCfg();
|
||||||
// inject all services
|
// inject all services
|
||||||
server.decorate<FastifyZodProvider["services"]>("services", {
|
server.decorate<FastifyZodProvider["services"]>("services", {
|
||||||
@@ -96,7 +136,12 @@ export const registerRoutes = async (
|
|||||||
orgRole: orgRoleService,
|
orgRole: orgRoleService,
|
||||||
apiKey: apiKeyService,
|
apiKey: apiKeyService,
|
||||||
authToken: tokenService,
|
authToken: tokenService,
|
||||||
superAdmin: superAdminService
|
superAdmin: superAdminService,
|
||||||
|
project: projectService,
|
||||||
|
projectMembership: projectMembershipService,
|
||||||
|
projectKey: projectKeyService,
|
||||||
|
projectEnv: projectEnvService,
|
||||||
|
projectRole: projectRoleService
|
||||||
});
|
});
|
||||||
|
|
||||||
server.decorate<FastifyZodProvider["store"]>("store", {
|
server.decorate<FastifyZodProvider["store"]>("store", {
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { registerAuthRoutes } from "./auth-router";
|
|||||||
import { registerInviteOrgRouter } from "./invite-org-router";
|
import { registerInviteOrgRouter } from "./invite-org-router";
|
||||||
import { registerOrgRouter } from "./organization-router";
|
import { registerOrgRouter } from "./organization-router";
|
||||||
import { registerPasswordRouter } from "./password-router";
|
import { registerPasswordRouter } from "./password-router";
|
||||||
|
import { registerProjectEnvRouter } from "./project-env-router";
|
||||||
|
import { registerProjectKeyRouter } from "./project-key-router";
|
||||||
|
import { registerProjectMembershipRouter } from "./project-membership-router";
|
||||||
|
import { registerProjectRouter } from "./project-router";
|
||||||
import { registerSsoRouter } from "./sso-router";
|
import { registerSsoRouter } from "./sso-router";
|
||||||
import { registerUserActionRouter } from "./user-action-router";
|
import { registerUserActionRouter } from "./user-action-router";
|
||||||
import { registerUserRouter } from "./user-router";
|
import { registerUserRouter } from "./user-router";
|
||||||
@@ -10,11 +14,20 @@ import { registerUserRouter } from "./user-router";
|
|||||||
export const registerV1Routes = async (server: FastifyZodProvider) => {
|
export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||||
await server.register(registerSsoRouter, { prefix: "/sso" });
|
await server.register(registerSsoRouter, { prefix: "/sso" });
|
||||||
await server.register(registerAuthRoutes, { prefix: "/auth" });
|
await server.register(registerAuthRoutes, { prefix: "/auth" });
|
||||||
// await server.register(registerSSORouter, { prefix: "/sso" });
|
|
||||||
await server.register(registerPasswordRouter, { prefix: "/password" });
|
await server.register(registerPasswordRouter, { prefix: "/password" });
|
||||||
await server.register(registerOrgRouter, { prefix: "/organization" });
|
await server.register(registerOrgRouter, { prefix: "/organization" });
|
||||||
await server.register(registerAdminRouter, { prefix: "/admin" });
|
await server.register(registerAdminRouter, { prefix: "/admin" });
|
||||||
await server.register(registerUserRouter, { prefix: "/user" });
|
await server.register(registerUserRouter, { prefix: "/user" });
|
||||||
await server.register(registerInviteOrgRouter, { prefix: "/invite-org" });
|
await server.register(registerInviteOrgRouter, { prefix: "/invite-org" });
|
||||||
await server.register(registerUserActionRouter, { prefix: "/user-action" });
|
await server.register(registerUserActionRouter, { prefix: "/user-action" });
|
||||||
|
|
||||||
|
await server.register(
|
||||||
|
async (projectServer) => {
|
||||||
|
await projectServer.register(registerProjectRouter);
|
||||||
|
await projectServer.register(registerProjectEnvRouter);
|
||||||
|
await projectServer.register(registerProjectKeyRouter);
|
||||||
|
await projectServer.register(registerProjectMembershipRouter);
|
||||||
|
},
|
||||||
|
{ prefix: "/workspace" }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { ProjectEnvironmentsSchema } from "@app/db/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/environments",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: z.string().trim(),
|
||||||
|
slug: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
workspace: z.string(),
|
||||||
|
environment: ProjectEnvironmentsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const environment = await server.services.projectEnv.createEnvironment({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "Successfully created new environment",
|
||||||
|
workspace: req.params.workspaceId,
|
||||||
|
environment
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/environments/:id",
|
||||||
|
method: "PATCH",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim(),
|
||||||
|
id: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
slug: z.string().trim().optional(),
|
||||||
|
name: z.string().trim().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
workspace: z.string(),
|
||||||
|
environment: ProjectEnvironmentsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const environment = await server.services.projectEnv.updateEnvironment({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
id: req.params.id,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "Successfully updated environment",
|
||||||
|
workspace: req.params.workspaceId,
|
||||||
|
environment
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/environments/:id",
|
||||||
|
method: "DELETE",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim(),
|
||||||
|
id: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
workspace: z.string(),
|
||||||
|
environment: ProjectEnvironmentsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const environment = await server.services.projectEnv.deleteEnvironment({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
id: req.params.id
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "Successfully deleted environment",
|
||||||
|
workspace: req.params.workspaceId,
|
||||||
|
environment
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerProjectKeyRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/key",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
key: z.object({
|
||||||
|
encryptedKey: z.string().trim(),
|
||||||
|
nonce: z.string().trim(),
|
||||||
|
userId: z.string().trim()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
await server.services.projectKey.uploadProjectKeys({
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
nonce: req.body.key.nonce,
|
||||||
|
receiverId: req.body.key.userId,
|
||||||
|
encryptedKey: req.body.key.encryptedKey
|
||||||
|
});
|
||||||
|
return { message: "Successfully uploaded key to workspace" };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { ProjectMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
||||||
|
// TODO(akhilmhdh-pg): missing adding multiple user workspace refer v2/membership
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/memberships",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
memberships: ProjectMembershipsSchema.merge(
|
||||||
|
z.object({
|
||||||
|
user: UsersSchema.pick({
|
||||||
|
email: true,
|
||||||
|
firstName: true,
|
||||||
|
lastName: true,
|
||||||
|
id: true
|
||||||
|
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true }))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.omit({ createdAt: true, updatedAt: true })
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const memberships = await server.services.projectMembership.getProjectMemberships({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
return { memberships };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/memberships/:membershipId",
|
||||||
|
method: "PATCH",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim(),
|
||||||
|
membershipId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
role: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
membership: ProjectMembershipsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const membership = await server.services.projectMembership.updateProjectMembership({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
membershipId: req.params.membershipId,
|
||||||
|
role: req.body.role
|
||||||
|
});
|
||||||
|
return { membership };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/memberships/:membershipId",
|
||||||
|
method: "DELETE",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim(),
|
||||||
|
membershipId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
membership: ProjectMembershipsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const membership = await server.services.projectMembership.deleteProjectMembership({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
membershipId: req.params.membershipId
|
||||||
|
});
|
||||||
|
return { membership };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ProjectKeysSchema,
|
||||||
|
ProjectMembershipsSchema,
|
||||||
|
ProjectsSchema,
|
||||||
|
UserEncryptionKeysSchema,
|
||||||
|
UsersSchema
|
||||||
|
} from "@app/db/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
export const registerProjectRouter = (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/keys",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
publicKeys: z
|
||||||
|
.object({
|
||||||
|
publicKey: z.string().optional(),
|
||||||
|
userId: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const publicKeys = await server.services.projectKey.getProjectPublicKeys({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
return { publicKeys };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/users",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
users: ProjectMembershipsSchema.merge(
|
||||||
|
z.object({
|
||||||
|
user: UsersSchema.pick({
|
||||||
|
email: true,
|
||||||
|
firstName: true,
|
||||||
|
lastName: true,
|
||||||
|
id: true
|
||||||
|
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true }))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.omit({ createdAt: true, updatedAt: true })
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const users = await server.services.projectMembership.getProjectMemberships({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
return { users };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspaces: ProjectsSchema.merge(
|
||||||
|
z.object({ environments: z.object({ name: z.string(), slug: z.string() }).array() })
|
||||||
|
).array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspaces = await server.services.project.getProjects(req.permission.id);
|
||||||
|
return { workspaces };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspace: ProjectsSchema.merge(
|
||||||
|
z.object({ environments: z.object({ name: z.string(), slug: z.string() }).array() })
|
||||||
|
).optional()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspace = await server.services.project.getAProject({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
return { workspace };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
workspaceName: z.string().trim(),
|
||||||
|
organizationId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspace: ProjectsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspace = await server.services.project.createProject({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
orgId: req.body.organizationId,
|
||||||
|
workspaceName: req.body.workspaceName
|
||||||
|
});
|
||||||
|
return { workspace };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId",
|
||||||
|
method: "DELETE",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
workspace: ProjectsSchema.optional()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspace = await server.services.project.deleteProject({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
return { workspace };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/name",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
workspace: ProjectsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspace = await server.services.project.updateName({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
name: req.body.name
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "Successfully changed workspace name",
|
||||||
|
workspace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/auto-capitalization",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
autoCapitalization: z.boolean()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
message: z.string(),
|
||||||
|
workspace: ProjectsSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const workspace = await server.services.project.toggleAutoCapitalization({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
autoCapitalization: req.body.autoCapitalization
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
message: "Successfully changed workspace settings",
|
||||||
|
workspace
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/invite-signup",
|
||||||
|
method: "POST",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
email: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
invitee: UsersSchema,
|
||||||
|
latestKey: ProjectKeysSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { invitee, latestKey } = await server.services.projectMembership.inviteUserToProject({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
projectId: req.params.workspaceId,
|
||||||
|
email: req.body.email
|
||||||
|
});
|
||||||
|
return { invitee, latestKey };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
import { registerMfaRouter } from "./mfa-router";
|
import { registerMfaRouter } from "./mfa-router";
|
||||||
|
import { registerProjectRouter } from "./project-router";
|
||||||
import { registerUserRouter } from "./user-router";
|
import { registerUserRouter } from "./user-router";
|
||||||
|
|
||||||
export const registerV2Routes = async (server: FastifyZodProvider) => {
|
export const registerV2Routes = async (server: FastifyZodProvider) => {
|
||||||
await server.register(registerMfaRouter, { prefix: "/auth" });
|
await server.register(registerMfaRouter, { prefix: "/auth" });
|
||||||
await server.register(registerUserRouter, { prefix: "/users" });
|
await server.register(registerUserRouter, { prefix: "/users" });
|
||||||
|
await server.register(
|
||||||
|
async (projectServer) => {
|
||||||
|
projectServer.register(registerProjectRouter);
|
||||||
|
},
|
||||||
|
{ prefix: "/workspace" }
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { ProjectKeysSchema } from "@app/db/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
url: "/:workspaceId/encrypted-key",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
workspaceId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: ProjectKeysSchema.merge(
|
||||||
|
z.object({
|
||||||
|
sender: z.object({
|
||||||
|
publicKey: z.string()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onResponse: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const key = await server.services.projectKey.getLatestProjectKey({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
});
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -60,7 +60,10 @@ export const orgRoleServiceFactory = ({
|
|||||||
if (existingRole && existingRole.id !== roleId)
|
if (existingRole && existingRole.id !== roleId)
|
||||||
throw new BadRequestError({ name: "Update Role", message: "Duplicate role" });
|
throw new BadRequestError({ name: "Update Role", message: "Duplicate role" });
|
||||||
}
|
}
|
||||||
const [updatedRole] = await orgRoleDal.update({ id: roleId, orgId }, { ...data });
|
const [updatedRole] = await orgRoleDal.update(
|
||||||
|
{ id: roleId, orgId },
|
||||||
|
{ ...data, permissions: data.permissions ? JSON.stringify(data.permissions) : undefined }
|
||||||
|
);
|
||||||
if (!updateRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
|
if (!updateRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
|
||||||
return updatedRole;
|
return updatedRole;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName,TProjectKeys } from "@app/db/schemas";
|
import { TableName, TProjectKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -35,8 +35,26 @@ export const projectKeyDalFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findAllProjectUserPubKeys = async (projectId: string) => {
|
||||||
|
try {
|
||||||
|
const pubKeys = await db(TableName.ProjectMembership)
|
||||||
|
.where({ projectId })
|
||||||
|
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
||||||
|
.join(
|
||||||
|
TableName.UserEncryptionKey,
|
||||||
|
`${TableName.Users}.id`,
|
||||||
|
`${TableName.UserEncryptionKey}.userId`
|
||||||
|
)
|
||||||
|
.select("userId", "publicKey");
|
||||||
|
return pubKeys;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Find all workspace pub keys" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...projectKeyOrm,
|
...projectKeyOrm,
|
||||||
|
findAllProjectUserPubKeys,
|
||||||
findLatestProjectKey
|
findLatestProjectKey
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,8 +57,18 @@ export const projectKeyServiceFactory = ({
|
|||||||
return latestKey;
|
return latestKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getProjectPublicKeys = async ({ actor, actorId, projectId }: TGetLatestProjectKeyDTO) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
return projectKeyDal.findAllProjectUserPubKeys(projectId);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uploadProjectKeys,
|
uploadProjectKeys,
|
||||||
|
getProjectPublicKeys,
|
||||||
getLatestProjectKey
|
getLatestProjectKey
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,20 +21,18 @@ export const projectMembershipDalFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership),
|
db.ref("id").withSchema(TableName.ProjectMembership),
|
||||||
db.ref("inviteEmail").withSchema(TableName.ProjectMembership),
|
db.ref("projectId").withSchema(TableName.ProjectMembership),
|
||||||
db.ref("orgId").withSchema(TableName.ProjectMembership),
|
|
||||||
db.ref("role").withSchema(TableName.ProjectMembership),
|
db.ref("role").withSchema(TableName.ProjectMembership),
|
||||||
db.ref("roleId").withSchema(TableName.ProjectMembership),
|
db.ref("roleId").withSchema(TableName.ProjectMembership),
|
||||||
db.ref("status").withSchema(TableName.ProjectMembership),
|
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
db.ref("lastName").withSchema(TableName.Users),
|
db.ref("lastName").withSchema(TableName.Users),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("publicKey").withSchema(TableName.UserEncryptionKey)
|
db.ref("publicKey").withSchema(TableName.UserEncryptionKey)
|
||||||
);
|
);
|
||||||
return members.map(({ email, firstName, lastName, userId, publicKey, ...data }) => ({
|
return members.map(({ email, firstName, lastName, publicKey, ...data }) => ({
|
||||||
...data,
|
...data,
|
||||||
user: { email, firstName, lastName, id: userId, publicKey }
|
user: { email, firstName, lastName, id: data.userId, publicKey }
|
||||||
}));
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all project members" });
|
throw new DatabaseError({ error, name: "Find all project members" });
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
await projectKeyDal.delete({ receiverId: deletedMembership.userId, projectId }, tx);
|
await projectKeyDal.delete({ receiverId: deletedMembership.userId, projectId }, tx);
|
||||||
|
return deletedMembership;
|
||||||
});
|
});
|
||||||
return membership;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
|
|
||||||
import { ProjectMembershipRole, TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
|
import { ProjectMembershipRole, TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
|
||||||
import {
|
|
||||||
OrgPermissionActions,
|
|
||||||
OrgPermissionSubjects
|
|
||||||
} from "@app/ee/services/permission/org-permission";
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import {
|
import {
|
||||||
projectAdminPermissions,
|
projectAdminPermissions,
|
||||||
projectMemberPermissions,
|
projectMemberPermissions,
|
||||||
projectNoAccessPermissions,
|
projectNoAccessPermissions,
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
projectViewerPermission
|
projectViewerPermission
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
@@ -22,7 +20,7 @@ type TProjectRoleServiceFactoryDep = {
|
|||||||
projectRoleDal: TProjectRoleDalFactory;
|
projectRoleDal: TProjectRoleDalFactory;
|
||||||
permissionService: Pick<
|
permissionService: Pick<
|
||||||
TPermissionServiceFactory,
|
TPermissionServiceFactory,
|
||||||
"getProjectPermission" | "getUserOrgPermission"
|
"getProjectPermission" | "getUserProjectPermission"
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,8 +38,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
ProjectPermissionActions.Create,
|
||||||
OrgPermissionSubjects.Role
|
ProjectPermissionSub.Role
|
||||||
);
|
);
|
||||||
const existingRole = await projectRoleDal.findOne({ slug: data.slug, projectId });
|
const existingRole = await projectRoleDal.findOne({ slug: data.slug, projectId });
|
||||||
if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" });
|
if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" });
|
||||||
@@ -62,8 +60,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
ProjectPermissionActions.Edit,
|
||||||
OrgPermissionSubjects.Role
|
ProjectPermissionSub.Role
|
||||||
);
|
);
|
||||||
if (data?.slug) {
|
if (data?.slug) {
|
||||||
const existingRole = await projectRoleDal.findOne({ slug: data.slug, projectId });
|
const existingRole = await projectRoleDal.findOne({ slug: data.slug, projectId });
|
||||||
@@ -83,8 +81,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
ProjectPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.Role
|
ProjectPermissionSub.Role
|
||||||
);
|
);
|
||||||
const [deletedRole] = await projectRoleDal.delete({ id: roleId, projectId });
|
const [deletedRole] = await projectRoleDal.delete({ id: roleId, projectId });
|
||||||
if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
|
if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
|
||||||
@@ -95,8 +93,8 @@ export const projectRoleServiceFactory = ({
|
|||||||
const listRoles = async (actor: ActorType, actorId: string, projectId: string) => {
|
const listRoles = async (actor: ActorType, actorId: string, projectId: string) => {
|
||||||
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Read,
|
ProjectPermissionActions.Read,
|
||||||
OrgPermissionSubjects.Role
|
ProjectPermissionSub.Role
|
||||||
);
|
);
|
||||||
const customRoles = await projectRoleDal.find({ projectId });
|
const customRoles = await projectRoleDal.find({ projectId });
|
||||||
const roles = [
|
const roles = [
|
||||||
@@ -149,8 +147,11 @@ export const projectRoleServiceFactory = ({
|
|||||||
return roles;
|
return roles;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUserPermission = async (userId: string, orgId: string) => {
|
const getUserPermission = async (userId: string, projectId: string) => {
|
||||||
const { permission, membership } = await permissionService.getUserOrgPermission(userId, orgId);
|
const { permission, membership } = await permissionService.getUserProjectPermission(
|
||||||
|
userId,
|
||||||
|
projectId
|
||||||
|
);
|
||||||
return { permissions: packRules(permission.rules), membership };
|
return { permissions: packRules(permission.rules), membership };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName,TProjects } from "@app/db/schemas";
|
import { TableName, TProjects } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { mergeOneToManyRelation, ormify } from "@app/lib/knex";
|
import { mergeOneToManyRelation, ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -90,27 +90,9 @@ export const projectDalFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findAllProjectUserPubKeys = async (projectId: string) => {
|
|
||||||
try {
|
|
||||||
const pubKeys = await db(TableName.ProjectMembership)
|
|
||||||
.where({ projectId })
|
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
|
||||||
.join(
|
|
||||||
TableName.UserEncryptionKey,
|
|
||||||
`${TableName.Users}.id`,
|
|
||||||
`${TableName.UserEncryptionKey}.userId`
|
|
||||||
)
|
|
||||||
.select("userId", "publicKey");
|
|
||||||
return pubKeys;
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Find all workspace pub keys" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...projectOrm,
|
...projectOrm,
|
||||||
findAllProjects,
|
findAllProjects,
|
||||||
findProjectById,
|
findProjectById
|
||||||
findAllProjectUserPubKeys
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -103,11 +103,28 @@ export const projectServiceFactory = ({
|
|||||||
return updatedProject;
|
return updatedProject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateName = async ({
|
||||||
|
projectId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
name
|
||||||
|
}: TGetProjectDTO & { name: string }) => {
|
||||||
|
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionSub.Settings
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedProject = await projectDal.updateById(projectId, { name });
|
||||||
|
return updatedProject;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createProject,
|
createProject,
|
||||||
deleteProject,
|
deleteProject,
|
||||||
getProjects,
|
getProjects,
|
||||||
getAProject,
|
getAProject,
|
||||||
toggleAutoCapitalization
|
toggleAutoCapitalization,
|
||||||
|
updateName
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,11 +60,12 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
|
|||||||
// Delete the row in the table (e.g. a user)
|
// Delete the row in the table (e.g. a user)
|
||||||
// #TODO: Add a pop-up that warns you that the user is going to be deleted.
|
// #TODO: Add a pop-up that warns you that the user is going to be deleted.
|
||||||
const handleDelete = async (membershipId: string) => {
|
const handleDelete = async (membershipId: string) => {
|
||||||
await deleteUserFromWorkspaceMutateAsync(membershipId);
|
await deleteUserFromWorkspaceMutateAsync({ membershipId, workspaceId });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRoleUpdate = async (index: number, e: string) => {
|
const handleRoleUpdate = async (index: number, e: string) => {
|
||||||
await updateUserWorkspaceRoleMutateAsync({
|
await updateUserWorkspaceRoleMutateAsync({
|
||||||
|
workspaceId,
|
||||||
membershipId: userData[index].membershipId,
|
membershipId: userData[index].membershipId,
|
||||||
role: e.toLowerCase()
|
role: e.toLowerCase()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ const encKeyKeys = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const fetchUserWsKey = async (workspaceID: string) => {
|
export const fetchUserWsKey = async (workspaceID: string) => {
|
||||||
const { data } = await apiRequest.get<{ latestKey: UserWsKeyPair }>(
|
const { data } = await apiRequest.get<UserWsKeyPair>(
|
||||||
`/api/v1/key/${workspaceID}/latest`
|
`/api/v2/workspace/${workspaceID}/encrypted-key`
|
||||||
);
|
);
|
||||||
|
|
||||||
return data.latestKey;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetUserWsKey = (workspaceID: string) =>
|
export const useGetUserWsKey = (workspaceID: string) =>
|
||||||
@@ -24,14 +24,11 @@ export const useGetUserWsKey = (workspaceID: string) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
// mutations
|
// mutations
|
||||||
export const uploadWsKey = async ({
|
export const uploadWsKey = async ({ workspaceId, userId, encryptedKey, nonce }: UploadWsKeyDTO) => {
|
||||||
workspaceId,
|
return apiRequest.post(`/api/v1/workspace/${workspaceId}/key`, {
|
||||||
userId,
|
key: { userId, encryptedKey, nonce }
|
||||||
encryptedKey,
|
});
|
||||||
nonce
|
};
|
||||||
}: UploadWsKeyDTO) => {
|
|
||||||
return apiRequest.post(`/api/v1/key/${workspaceId}`, { key: { userId, encryptedKey, nonce } })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUploadWsKey = () =>
|
export const useUploadWsKey = () =>
|
||||||
useMutation<{}, {}, UploadWsKeyDTO>({
|
useMutation<{}, {}, UploadWsKeyDTO>({
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ export const workspaceKeys = {
|
|||||||
getAllUserWorkspace: ["workspaces"] as const,
|
getAllUserWorkspace: ["workspaces"] as const,
|
||||||
getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const,
|
getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const,
|
||||||
getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }] as const,
|
getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }] as const,
|
||||||
getWorkspaceIdentityMemberships: (workspaceId: string) => [{ workspaceId }, "workspace-identity-memberships"] as const
|
getWorkspaceIdentityMemberships: (workspaceId: string) =>
|
||||||
|
[{ workspaceId }, "workspace-identity-memberships"] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchWorkspaceById = async (workspaceId: string) => {
|
const fetchWorkspaceById = async (workspaceId: string) => {
|
||||||
@@ -221,10 +222,10 @@ export const useCreateWsEnvironment = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation<{}, {}, CreateEnvironmentDTO>({
|
return useMutation<{}, {}, CreateEnvironmentDTO>({
|
||||||
mutationFn: ({ workspaceID, environmentName, environmentSlug }) => {
|
mutationFn: ({ workspaceId, name, slug }) => {
|
||||||
return apiRequest.post(`/api/v2/workspace/${workspaceID}/environments`, {
|
return apiRequest.post(`/api/v1/workspace/${workspaceId}/environments`, {
|
||||||
environmentName,
|
name,
|
||||||
environmentSlug
|
slug
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -238,13 +239,13 @@ export const useReorderWsEnvironment = () => {
|
|||||||
|
|
||||||
return useMutation<{}, {}, ReorderEnvironmentsDTO>({
|
return useMutation<{}, {}, ReorderEnvironmentsDTO>({
|
||||||
mutationFn: ({
|
mutationFn: ({
|
||||||
workspaceID,
|
workspaceId,
|
||||||
environmentSlug,
|
environmentSlug,
|
||||||
environmentName,
|
environmentName,
|
||||||
otherEnvironmentSlug,
|
otherEnvironmentSlug,
|
||||||
otherEnvironmentName
|
otherEnvironmentName
|
||||||
}) => {
|
}) => {
|
||||||
return apiRequest.patch(`/api/v2/workspace/${workspaceID}/environments`, {
|
return apiRequest.patch(`/api/v2/workspace/${workspaceId}/environments`, {
|
||||||
environmentSlug,
|
environmentSlug,
|
||||||
environmentName,
|
environmentName,
|
||||||
otherEnvironmentSlug,
|
otherEnvironmentSlug,
|
||||||
@@ -261,11 +262,10 @@ export const useUpdateWsEnvironment = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation<{}, {}, UpdateEnvironmentDTO>({
|
return useMutation<{}, {}, UpdateEnvironmentDTO>({
|
||||||
mutationFn: ({ workspaceID, environmentName, environmentSlug, oldEnvironmentSlug }) => {
|
mutationFn: ({ workspaceId, id, name, slug }) => {
|
||||||
return apiRequest.put(`/api/v2/workspace/${workspaceID}/environments`, {
|
return apiRequest.put(`/api/v2/workspace/${workspaceId}/environments/${id}`, {
|
||||||
environmentName,
|
name,
|
||||||
environmentSlug,
|
slug
|
||||||
oldEnvironmentSlug
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
@@ -278,10 +278,8 @@ export const useDeleteWsEnvironment = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation<{}, {}, DeleteEnvironmentDTO>({
|
return useMutation<{}, {}, DeleteEnvironmentDTO>({
|
||||||
mutationFn: ({ workspaceID, environmentSlug }) => {
|
mutationFn: ({ id, workspaceId }) => {
|
||||||
return apiRequest.delete(`/api/v2/workspace/${workspaceID}/environments`, {
|
return apiRequest.delete(`/api/v1/workspace/${workspaceId}/environments/${id}`);
|
||||||
data: { environmentSlug }
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
@@ -328,14 +326,20 @@ export const useDeleteUserFromWorkspace = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (membershipId: string) => {
|
mutationFn: async ({
|
||||||
|
membershipId,
|
||||||
|
workspaceId
|
||||||
|
}: {
|
||||||
|
workspaceId: string;
|
||||||
|
membershipId: string;
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
data: { deletedMembership }
|
data: { deletedMembership }
|
||||||
} = await apiRequest.delete(`/api/v1/membership/${membershipId}`);
|
} = await apiRequest.delete(`/api/v1/${workspaceId}/membership/${membershipId}`);
|
||||||
return deletedMembership;
|
return deletedMembership;
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(res.workspace));
|
queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(workspaceId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -343,10 +347,18 @@ export const useDeleteUserFromWorkspace = () => {
|
|||||||
export const useUpdateUserWorkspaceRole = () => {
|
export const useUpdateUserWorkspaceRole = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({ membershipId, role }: { membershipId: string; role: string }) => {
|
mutationFn: async ({
|
||||||
|
membershipId,
|
||||||
|
role,
|
||||||
|
workspaceId
|
||||||
|
}: {
|
||||||
|
membershipId: string;
|
||||||
|
role: string;
|
||||||
|
workspaceId: string;
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
data: { membership }
|
data: { membership }
|
||||||
} = await apiRequest.post(`/api/v1/membership/${membershipId}/change-role`, {
|
} = await apiRequest.post(`/api/v1/${workspaceId}/membership/${membershipId}`, {
|
||||||
role
|
role
|
||||||
});
|
});
|
||||||
return membership;
|
return membership;
|
||||||
@@ -369,12 +381,14 @@ export const useAddIdentityToWorkspace = () => {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
role?: string;
|
role?: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { identityMembership }
|
data: { identityMembership }
|
||||||
} = await apiRequest.post(`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`, {
|
} = await apiRequest.post(
|
||||||
role
|
`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`,
|
||||||
});
|
{
|
||||||
|
role
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return identityMembership;
|
return identityMembership;
|
||||||
},
|
},
|
||||||
@@ -396,12 +410,14 @@ export const useUpdateIdentityWorkspaceRole = () => {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
role?: string;
|
role?: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { identityMembership }
|
data: { identityMembership }
|
||||||
} = await apiRequest.patch(`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`, {
|
} = await apiRequest.patch(
|
||||||
role
|
`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`,
|
||||||
});
|
{
|
||||||
|
role
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return identityMembership;
|
return identityMembership;
|
||||||
},
|
},
|
||||||
@@ -416,14 +432,16 @@ export const useDeleteIdentityFromWorkspace = () => {
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
identityId,
|
identityId,
|
||||||
workspaceId,
|
workspaceId
|
||||||
}: {
|
}: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
data: { identityMembership }
|
data: { identityMembership }
|
||||||
} = await apiRequest.delete(`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`);
|
} = await apiRequest.delete(
|
||||||
|
`/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`
|
||||||
|
);
|
||||||
return identityMembership;
|
return identityMembership;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { workspaceId }) => {
|
onSuccess: (_, { workspaceId }) => {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export type Workspace = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type WorkspaceEnv = {
|
export type WorkspaceEnv = {
|
||||||
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
isReadDenied: boolean;
|
isReadDenied: boolean;
|
||||||
@@ -36,13 +37,13 @@ export type ToggleAutoCapitalizationDTO = { workspaceID: string; state: boolean
|
|||||||
export type DeleteWorkspaceDTO = { workspaceID: string };
|
export type DeleteWorkspaceDTO = { workspaceID: string };
|
||||||
|
|
||||||
export type CreateEnvironmentDTO = {
|
export type CreateEnvironmentDTO = {
|
||||||
workspaceID: string;
|
workspaceId: string;
|
||||||
environmentSlug: string;
|
name: string;
|
||||||
environmentName: string;
|
slug: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReorderEnvironmentsDTO = {
|
export type ReorderEnvironmentsDTO = {
|
||||||
workspaceID: string;
|
workspaceId: string;
|
||||||
environmentSlug: string;
|
environmentSlug: string;
|
||||||
environmentName: string;
|
environmentName: string;
|
||||||
otherEnvironmentSlug: string;
|
otherEnvironmentSlug: string;
|
||||||
@@ -50,10 +51,10 @@ export type ReorderEnvironmentsDTO = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateEnvironmentDTO = {
|
export type UpdateEnvironmentDTO = {
|
||||||
workspaceID: string;
|
workspaceId: string;
|
||||||
oldEnvironmentSlug: string;
|
id: string;
|
||||||
environmentSlug: string;
|
name?: string;
|
||||||
environmentName: string;
|
slug?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DeleteEnvironmentDTO = { workspaceID: string; environmentSlug: string };
|
export type DeleteEnvironmentDTO = { workspaceId: string; id: string };
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export const MemberListTab = () => {
|
|||||||
if (!currentOrg?.id) return;
|
if (!currentOrg?.id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await removeUserFromWorkspace(membershipId);
|
await removeUserFromWorkspace({ workspaceId, membershipId });
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Successfully removed user from workspace",
|
text: "Successfully removed user from workspace",
|
||||||
type: "success"
|
type: "success"
|
||||||
@@ -182,7 +182,7 @@ export const MemberListTab = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateUserWorkspaceRole({ membershipId, role });
|
await updateUserWorkspaceRole({ membershipId, role, workspaceId });
|
||||||
createNotification({
|
createNotification({
|
||||||
text: "Successfully updated user role",
|
text: "Successfully updated user role",
|
||||||
type: "success"
|
type: "success"
|
||||||
|
|||||||
+3
-3
@@ -34,9 +34,9 @@ export const AddEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpToggle
|
|||||||
if (!currentWorkspace?.id) return;
|
if (!currentWorkspace?.id) return;
|
||||||
|
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
workspaceID: currentWorkspace.id,
|
workspaceId: currentWorkspace.id,
|
||||||
environmentName,
|
name: environmentName,
|
||||||
environmentSlug
|
slug: environmentSlug
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
|
|||||||
+4
-6
@@ -38,13 +38,13 @@ export const EnvironmentSection = () => {
|
|||||||
"upgradePlan"
|
"upgradePlan"
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
const onEnvDeleteSubmit = async (environmentSlug: string) => {
|
const onEnvDeleteSubmit = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
if (!currentWorkspace?.id) return;
|
if (!currentWorkspace?.id) return;
|
||||||
|
|
||||||
await deleteWsEnvironment.mutateAsync({
|
await deleteWsEnvironment.mutateAsync({
|
||||||
workspaceID: currentWorkspace.id,
|
workspaceId: currentWorkspace.id,
|
||||||
environmentSlug
|
id
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -116,9 +116,7 @@ export const EnvironmentSection = () => {
|
|||||||
}?`}
|
}?`}
|
||||||
onChange={(isOpen) => handlePopUpToggle("deleteEnv", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("deleteEnv", isOpen)}
|
||||||
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ""}
|
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ""}
|
||||||
onDeleteApproved={() =>
|
onDeleteApproved={() => onEnvDeleteSubmit((popUp?.deleteEnv?.data as { id: string })?.id)}
|
||||||
onEnvDeleteSubmit((popUp?.deleteEnv?.data as { slug: string })?.slug)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<UpgradePlanModal
|
<UpgradePlanModal
|
||||||
isOpen={popUp.upgradePlan.isOpen}
|
isOpen={popUp.upgradePlan.isOpen}
|
||||||
|
|||||||
+7
-5
@@ -24,10 +24,12 @@ type Props = {
|
|||||||
popUpName: keyof UsePopUpState<["updateEnv", "deleteEnv", "upgradePlan"]>,
|
popUpName: keyof UsePopUpState<["updateEnv", "deleteEnv", "upgradePlan"]>,
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
slug
|
slug,
|
||||||
|
id
|
||||||
}: {
|
}: {
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
id: string;
|
||||||
}
|
}
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
@@ -56,7 +58,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
const indexToSwap = shouldMoveUp ? indexOfEnv - 1 : indexOfEnv + 1;
|
const indexToSwap = shouldMoveUp ? indexOfEnv - 1 : indexOfEnv + 1;
|
||||||
|
|
||||||
await reorderWsEnvironment.mutateAsync({
|
await reorderWsEnvironment.mutateAsync({
|
||||||
workspaceID: currentWorkspace.id,
|
workspaceId: currentWorkspace.id,
|
||||||
environmentSlug: slug,
|
environmentSlug: slug,
|
||||||
environmentName: name,
|
environmentName: name,
|
||||||
otherEnvironmentSlug: currentWorkspace.environments[indexToSwap].slug,
|
otherEnvironmentSlug: currentWorkspace.environments[indexToSwap].slug,
|
||||||
@@ -90,7 +92,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
{isLoading && <TableSkeleton columns={3} innerKey="project-envs" />}
|
{isLoading && <TableSkeleton columns={3} innerKey="project-envs" />}
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
currentWorkspace &&
|
currentWorkspace &&
|
||||||
currentWorkspace.environments.map(({ name, slug }, pos) => (
|
currentWorkspace.environments.map(({ name, slug, id }, pos) => (
|
||||||
<Tr key={name}>
|
<Tr key={name}>
|
||||||
<Td>{name}</Td>
|
<Td>{name}</Td>
|
||||||
<Td>{slug}</Td>
|
<Td>{slug}</Td>
|
||||||
@@ -142,7 +144,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
<IconButton
|
<IconButton
|
||||||
className="mr-3 py-2"
|
className="mr-3 py-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handlePopUpOpen("updateEnv", { name, slug });
|
handlePopUpOpen("updateEnv", { name, slug, id });
|
||||||
}}
|
}}
|
||||||
isDisabled={!isAllowed}
|
isDisabled={!isAllowed}
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
@@ -160,7 +162,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handlePopUpOpen("deleteEnv", { name, slug });
|
handlePopUpOpen("deleteEnv", { name, slug, id });
|
||||||
}}
|
}}
|
||||||
size="lg"
|
size="lg"
|
||||||
colorSchema="danger"
|
colorSchema="danger"
|
||||||
|
|||||||
+5
-5
@@ -29,17 +29,17 @@ export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpTog
|
|||||||
resolver: yupResolver(schema)
|
resolver: yupResolver(schema)
|
||||||
});
|
});
|
||||||
|
|
||||||
const oldEnvironmentSlug = (popUp?.updateEnv?.data as { slug: string })?.slug;
|
const oldEnvId = (popUp?.updateEnv?.data as { id: string })?.id;
|
||||||
|
|
||||||
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
|
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (!currentWorkspace?.id) return;
|
if (!currentWorkspace?.id) return;
|
||||||
|
|
||||||
await mutateAsync({
|
await mutateAsync({
|
||||||
workspaceID: currentWorkspace.id,
|
workspaceId: currentWorkspace.id,
|
||||||
environmentName,
|
name: environmentName,
|
||||||
environmentSlug,
|
slug: environmentSlug,
|
||||||
oldEnvironmentSlug
|
id: oldEnvId
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve"
|
||||||
"incremental": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"next-i18next.config.js",
|
"next-i18next.config.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user