diff --git a/backend/src/controllers/v1/membershipController.ts b/backend/src/controllers/v1/membershipController.ts index 49a169f8a..bc2dc0e8d 100644 --- a/backend/src/controllers/v1/membershipController.ts +++ b/backend/src/controllers/v1/membershipController.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; import { Types } from "mongoose"; -import { IUser, Key, Membership, MembershipOrg, User } from "../../models"; +import { IUser, Key, Membership, MembershipOrg, User, Workspace } from "../../models"; import { EventType } from "../../ee/models"; import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership"; import { sendMail } from "../../helpers/nodemailer"; @@ -17,6 +17,7 @@ import { import { ForbiddenError } from "@casl/ability"; import Role from "../../models/role"; import { BadRequestError } from "../../utils/errors"; +import { InviteUserToWorkspaceV1 } from "../../validation/workspace"; /** * Check that user is a member of workspace with id [workspaceId] @@ -182,8 +183,15 @@ export const changeMembershipRole = async (req: Request, res: Response) => { * @returns */ export const inviteUserToWorkspace = async (req: Request, res: Response) => { - const { workspaceId } = req.params; - const { email }: { email: string } = req.body; + const { + params: { workspaceId }, + body: { email } + } = await validateRequest(InviteUserToWorkspaceV1, req); + const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Create, + ProjectPermissionSub.Member + ); const invitee = await User.findOne({ email @@ -200,11 +208,13 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => { if (inviteeMembership) throw new Error("Failed to add existing member of workspace"); + const workspace = await Workspace.findById(workspaceId); + if (!workspace) throw new Error("Failed to find workspace"); // validate invitee's organization membership - ensure that only // (accepted) organization members can be added to the workspace const membershipOrg = await MembershipOrg.findOne({ user: invitee._id, - organization: req.membership.workspace.organization, + organization: workspace.organization, status: ACCEPTED }); @@ -232,7 +242,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => { substitutions: { inviterFirstName: req.user.firstName, inviterEmail: req.user.email, - workspaceName: req.membership.workspace.name, + workspaceName: workspace.name, callback_url: (await getSiteURL()) + "/login" } }); diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index ca94bc9ce..e2b405483 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -368,7 +368,7 @@ export const deleteSecretByNameRaw = async (req: Request, res: Response) => { */ export const getSecrets = async (req: Request, res: Response) => { const { - query: { secretPath, environment, workspaceId, include_imports: includeImports,folderId } + query: { secretPath, environment, workspaceId, include_imports: includeImports, folderId } } = await validateRequest(reqValidator.GetSecretsV3, req); if (req.user?._id) { @@ -468,7 +468,6 @@ export const createSecret = async (req: Request, res: Response) => { const { body: { workspaceId, - secretName, secretPath, environment, metadata, @@ -482,7 +481,8 @@ export const createSecret = async (req: Request, res: Response) => { secretKeyCiphertext, secretValueCiphertext, secretCommentCiphertext - } + }, + params: { secretName } } = await validateRequest(reqValidator.CreateSecretV3, req); if (req.user?._id) { diff --git a/backend/src/routes/v1/workspace.ts b/backend/src/routes/v1/workspace.ts index c8acc1846..b6a28819a 100644 --- a/backend/src/routes/v1/workspace.ts +++ b/backend/src/routes/v1/workspace.ts @@ -1,8 +1,7 @@ import express from "express"; const router = express.Router(); -import { body, param } from "express-validator"; -import { requireAuth, requireWorkspaceAuth, validateRequest } from "../../middleware"; -import { ADMIN, AuthMode, MEMBER } from "../../variables"; +import { requireAuth } from "../../middleware"; +import { AuthMode } from "../../variables"; import { membershipController, workspaceController } from "../../controllers/v1"; router.get( @@ -42,7 +41,7 @@ router.post( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - workspaceController.deleteWorkspace + workspaceController.createWorkspace ); router.post( @@ -50,13 +49,6 @@ router.post( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - requireWorkspaceAuth({ - acceptedRoles: [ADMIN, MEMBER], - locationWorkspaceId: "params" - }), - param("workspaceId").exists().trim(), - body("name").exists().trim().notEmpty(), - validateRequest, workspaceController.changeWorkspaceName ); diff --git a/backend/src/validation/auth.ts b/backend/src/validation/auth.ts index e9ffec8de..f32fc1197 100644 --- a/backend/src/validation/auth.ts +++ b/backend/src/validation/auth.ts @@ -9,7 +9,7 @@ export const BeginEmailSignUpV1 = z.object({ export const VerifyEmailSignUpV1 = z.object({ body: z.object({ email: z.string().email().trim(), - code: z.string().email().trim() + code: z.string().trim() }) }); diff --git a/backend/src/validation/secrets.ts b/backend/src/validation/secrets.ts index 0e733112f..c4529039b 100644 --- a/backend/src/validation/secrets.ts +++ b/backend/src/validation/secrets.ts @@ -228,7 +228,7 @@ export const GetSecretsRawV3 = z.object({ workspaceId: z.string().trim(), environment: z.string().trim(), secretPath: z.string().trim().default("/"), - folderId:z.string().trim().optional(), + folderId: z.string().trim().optional(), include_imports: z .enum(["true", "false"]) .default("false") @@ -319,7 +319,6 @@ export const CreateSecretV3 = z.object({ environment: z.string().trim(), type: z.enum([SECRET_SHARED, SECRET_PERSONAL]), secretPath: z.string().trim().default("/"), - secretName: z.string().trim(), secretKeyCiphertext: z.string().trim(), secretKeyIV: z.string().trim(), secretKeyTag: z.string().trim(), @@ -332,6 +331,9 @@ export const CreateSecretV3 = z.object({ metadata: z.object({ source: z.string() }) + }), + params: z.object({ + secretName: z.string().trim() }) }); diff --git a/frontend/src/views/Org/MembersPage/MembersPage.tsx b/frontend/src/views/Org/MembersPage/MembersPage.tsx index 57b69c5b7..9e7855e53 100644 --- a/frontend/src/views/Org/MembersPage/MembersPage.tsx +++ b/frontend/src/views/Org/MembersPage/MembersPage.tsx @@ -23,7 +23,7 @@ export const MembersPage = withPermission( const orgId = currentOrg?._id || ""; - const { data: roles } = useGetRoles({ + const { data: roles, isLoading: isRolesLoading } = useGetRoles({ orgId }); @@ -48,11 +48,17 @@ export const MembersPage = withPermission( animate={{ opacity: 1, translateX: 0 }} exit={{ opacity: 0, translateX: 30 }} > - []} /> + []} + isRolesLoading={isRolesLoading} + /> - []} /> + []} + isRolesLoading={isRolesLoading} + /> diff --git a/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx b/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx index 459d5f47a..c08a1cf1e 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx @@ -66,6 +66,7 @@ import { useFetchServerStatus } from "@app/hooks/api/serverDetails"; type Props = { roles?: TRole[]; + isRolesLoading?: boolean; }; const addMemberFormSchema = yup.object({ @@ -74,7 +75,7 @@ const addMemberFormSchema = yup.object({ type TAddMemberForm = yup.InferType; -export const OrgMembersTable = ({ roles = [] }: Props) => { +export const OrgMembersTable = ({ roles = [], isRolesLoading }: Props) => { const router = useRouter(); const { createNotification } = useNotificationContext(); @@ -292,7 +293,7 @@ export const OrgMembersTable = ({ roles = [] }: Props) => { setInviteLinkCopied.on(); }; - const isLoading = isMembersLoading || IsWsMembershipLoading; + const isLoading = isMembersLoading || IsWsMembershipLoading || isRolesLoading; return (
diff --git a/frontend/src/views/Project/MembersPage/MembersPage.tsx b/frontend/src/views/Project/MembersPage/MembersPage.tsx index 3c6a1f680..4c83e087f 100644 --- a/frontend/src/views/Project/MembersPage/MembersPage.tsx +++ b/frontend/src/views/Project/MembersPage/MembersPage.tsx @@ -47,7 +47,7 @@ export const MembersPage = withProjectPermission( animate={{ opacity: 1, translateX: 0 }} exit={{ opacity: 0, translateX: 30 }} > - []} /> + []} isRolesLoading={isRolesLoading} /> diff --git a/frontend/src/views/Project/MembersPage/components/MemberListTab/MemberListTab.tsx b/frontend/src/views/Project/MembersPage/components/MemberListTab/MemberListTab.tsx index bcf272607..3dddd4ef8 100644 --- a/frontend/src/views/Project/MembersPage/components/MemberListTab/MemberListTab.tsx +++ b/frontend/src/views/Project/MembersPage/components/MemberListTab/MemberListTab.tsx @@ -54,6 +54,7 @@ import { TRole } from "@app/hooks/api/roles/types"; type Props = { roles?: TRole[]; + isRolesLoading?: boolean; }; const addMemberFormSchema = z.object({ @@ -62,7 +63,7 @@ const addMemberFormSchema = z.object({ type TAddMemberForm = z.infer; -export const MemberListTab = ({ roles = [] }: Props) => { +export const MemberListTab = ({ roles = [], isRolesLoading }: Props) => { const { createNotification } = useNotificationContext(); const { t } = useTranslation(); @@ -227,7 +228,7 @@ export const MemberListTab = ({ roles = [] }: Props) => { } }; - const isLoading = isMembersLoading; + const isLoading = isMembersLoading || isRolesLoading; return (