feat: completed all nit changes in review

This commit is contained in:
=
2024-10-22 13:20:05 +05:30
parent 2afc6b133e
commit 3b2b8ca013
18 changed files with 87 additions and 60 deletions

View File

@@ -20,7 +20,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit
},
schema: {
description: "Create an additional privilege for identity.",
description: "Add an additional privilege for identity.",
security: [
{
bearerAuth: []
@@ -91,7 +91,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit
},
schema: {
description: "Update a specific privilege of an identity.",
description: "Update a specific identity privilege.",
security: [
{
bearerAuth: []
@@ -167,7 +167,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit
},
schema: {
description: "Delete a specific privilege of an identity.",
description: "Delete the specified identity privilege.",
security: [
{
bearerAuth: []
@@ -202,7 +202,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit
},
schema: {
description: "Retrieve details of a specific privilege by privilege id.",
description: "Retrieve details of a specific privilege by id.",
security: [
{
bearerAuth: []
@@ -237,7 +237,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit
},
schema: {
description: "Retrieve details of a specific privilege by privilege slug.",
description: "Retrieve details of a specific privilege by slug.",
security: [
{
bearerAuth: []
@@ -277,7 +277,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit
},
schema: {
description: "List of a specific privilege of an identity in a project.",
description: "List privileges for the specified identity by project.",
security: [
{
bearerAuth: []

View File

@@ -76,7 +76,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
slug,
projectMembershipId: identityProjectMembership.id
});
if (existingSlug) throw new BadRequestError({ message: "Additional privilege of provided slug exist" });
if (existingSlug) throw new BadRequestError({ message: "Additional privilege with provided slug already exists" });
if (!dto.isTemporary) {
const additionalPrivilege = await identityProjectAdditionalPrivilegeDAL.create({
@@ -117,7 +117,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod
}: TUpdateIdentityPrivilegeByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" });
if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership)
@@ -150,7 +150,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
projectMembershipId: identityProjectMembership.id
});
if (existingSlug && existingSlug.id !== identityPrivilege.id)
throw new BadRequestError({ message: "Additional privilege of provided slug exist" });
throw new BadRequestError({ message: "Additional privilege with provided slug already exists" });
}
const isTemporary = typeof data?.isTemporary !== "undefined" ? data.isTemporary : identityPrivilege.isTemporary;
@@ -189,7 +189,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
const deleteById = async ({ actorId, id, actor, actorOrgId, actorAuthMethod }: TDeleteIdentityPrivilegeByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" });
if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership)
@@ -231,7 +231,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod
}: TGetIdentityPrivilegeDetailsByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" });
if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership)
@@ -264,7 +264,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod
}: TGetIdentityPrivilegeDetailsBySlugDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: "Project not found" });
if (!project) throw new NotFoundError({ message: `Project with slug ${slug} not found` });
const projectId = project.id;
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });

View File

@@ -2,8 +2,10 @@ import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, unpackRules } from "@casl/ability/extra";
import ms from "ms";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { UnpackedPermissionSchema } from "@app/server/routes/santizedSchemas/permission";
import { ActorType } from "@app/services/auth/auth-type";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { TPermissionServiceFactory } from "../permission/permission-service";
@@ -50,7 +52,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TCreateUserPrivilegeDTO) => {
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
if (!projectMembership)
throw new NotFoundError({ message: `Project membership with ID '${projectMembershipId}' not found` });
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} found` });
const { permission } = await permissionService.getProjectPermission(
actor,
@@ -60,13 +62,24 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const { permission: entityPermission } = await permissionService.getProjectPermission(
ActorType.USER,
projectMembership.userId,
projectMembership.projectId,
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, entityPermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to update more privileged identity" });
const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({
slug,
projectId: projectMembership.projectId,
userId: projectMembership.userId
});
if (existingSlug) throw new BadRequestError({ message: "Additional privilege of provided slug exist" });
if (existingSlug)
throw new BadRequestError({ message: `Additional privilege with provided slug ${slug} already exists` });
if (!dto.isTemporary) {
const additionalPrivilege = await projectUserAdditionalPrivilegeDAL.create({
@@ -109,7 +122,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TUpdateUserPrivilegeDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` });
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId,
@@ -129,6 +142,16 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const { permission: entityPermission } = await permissionService.getProjectPermission(
ActorType.USER,
projectMembership.userId,
projectMembership.projectId,
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, entityPermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to update more privileged identity" });
if (dto?.slug) {
const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({
@@ -137,7 +160,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
projectId: projectMembership.projectId
});
if (existingSlug && existingSlug.id !== userPrivilege.id)
throw new BadRequestError({ message: "Additional privilege of provided slug exist" });
throw new BadRequestError({ message: `Additional privilege with provided slug ${dto.slug} already exists` });
}
const isTemporary = typeof dto?.isTemporary !== "undefined" ? dto.isTemporary : userPrivilege.isTemporary;
@@ -178,7 +201,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
const deleteById = async ({ actorId, actor, actorOrgId, actorAuthMethod, privilegeId }: TDeleteUserPrivilegeDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` });
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId,
@@ -214,7 +237,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TGetUserPrivilegeDetailsDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` });
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId,
@@ -249,7 +272,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TListUserPrivilegesDTO) => {
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
if (!projectMembership)
throw new NotFoundError({ message: `Project membership with ID '${projectMembershipId}' not found` });
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} not found` });
const { permission } = await permissionService.getProjectPermission(
actor,

View File

@@ -974,27 +974,27 @@ export const PROJECT_USER_ADDITIONAL_PRIVILEGE = {
export const IDENTITY_ADDITIONAL_PRIVILEGE_V2 = {
CREATE: {
identityId: "The ID of the identity to create.",
identityId: "The ID of the identity to create the privilege for",
projectId: "The ID of the project of the identity in.",
slug: "The slug of the privilege to create.",
permission: "The permission for the privilege.",
isTemporary: "Whether the privilege is temporary.",
isTemporary: "Whether the privilege is temporary or permanent.",
temporaryMode: "Type of temporary access given. Types: relative",
temporaryRange: "TTL for the temporay time. Eg: 1m, 1h, 1d",
temporaryAccessStartTime: "ISO time for which temporary access should begin."
temporaryRange: "The TTL for the temporary access given",
temporaryAccessStartTime: "The start time in ISO format when the temporary access should begin."
},
UPDATE: {
id: "The id of the privilege of the identity.",
id: "The ID of the identity privilege.",
identityId: "The ID of the identity to update.",
slug: "The slug of the privilege to update.",
privilegePermission: "The permission for the privilege.",
isTemporary: "Whether the privilege is temporary.",
temporaryMode: "Type of temporary access given. Types: relative",
temporaryRange: "TTL for the temporay time. Eg: 1m, 1h, 1d",
temporaryAccessStartTime: "ISO time for which temporary access should begin."
temporaryRange: "The TTL for the temporary access given",
temporaryAccessStartTime: "The start time in ISO format when the temporary access should begin."
},
DELETE: {
id: "the id of the privilege of the identity.",
id: "The ID of the identity privilege.",
identityId: "The ID of the identity to delete.",
slug: "The slug of the privilege to delete."
},
@@ -1004,10 +1004,10 @@ export const IDENTITY_ADDITIONAL_PRIVILEGE_V2 = {
slug: "The slug of the privilege."
},
GET_BY_ID: {
id: "The id of the privilege of the identity."
id: "The ID of the identity privilege."
},
LIST: {
projectId: "The ID of the project of the identity in.",
projectId: "The ID of the project that the identity is in.",
identityId: "The ID of the identity to list."
}
};

View File

@@ -118,7 +118,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const membership = await server.services.projectMembership.getProjectMembershipById({
actorId: req.permission.id,

View File

@@ -38,7 +38,7 @@ const glob: JsInterpreter<FieldCondition<string>> = (node, object, context) => {
const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob });
export const roleQueryKeys = {
getProjectRoles: (projectId: string) => ["roles", { projectSlug: projectId }] as const,
getProjectRoles: (projectId: string) => ["roles", { projectId }] as const,
getProjectRoleBySlug: (projectId: string, roleSlug: string) =>
["roles", { projectId, roleSlug }] as const,
getOrgRoles: (orgId: string) => ["org-roles", { orgId }] as const,

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next";
import Head from "next/head";

View File

@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next";
import Head from "next/head";

View File

@@ -56,10 +56,10 @@ export const IdentityDetailsPage = withProjectPermission(
</h3>
<div>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
I={ProjectPermissionActions.Delete}
a={ProjectPermissionSub.Identity}
renderTooltip
allowedLabel="Edit role"
allowedLabel="Remove from project"
>
{(isAllowed) => (
<Button

View File

@@ -206,9 +206,7 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({
<IconButton ariaLabel="go-back" variant="plain" onClick={onGoBack}>
<FontAwesomeIcon icon={faChevronLeft} />
</IconButton>
<h3 className="text-lg font-semibold text-mineshaft-100">
Modify Additional Privilege
</h3>
<h3 className="text-lg font-semibold text-mineshaft-100">Edit Additional Privilege</h3>
</div>
<div className="flex items-center space-x-4">
{isDirty && (

View File

@@ -98,7 +98,7 @@ export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDe
>
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100">
Project Additional Privilege
Project Additional Privileges
</h3>
<ProjectPermissionCan
@@ -174,7 +174,7 @@ export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDe
}}
onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)}
>
<Td className="capitalize">{privilegeDetails.slug}</Td>
<Td>{privilegeDetails.slug}</Td>
<Td>
<Tooltip asChild={false} content={toolTipText}>
<Tag

View File

@@ -72,7 +72,7 @@ export const IdentityRoleDetailsSection = ({
I={ProjectPermissionActions.Edit}
a={ProjectPermissionSub.Identity}
renderTooltip
allowedLabel="Edit role"
allowedLabel="Edit Role(s)"
>
{(isAllowed) => (
<IconButton

View File

@@ -54,10 +54,10 @@ export const MemberDetailsPage = withProjectPermission(
<h3 className="text-xl font-semibold text-mineshaft-100">Project User Access</h3>
<div>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
I={ProjectPermissionActions.Delete}
a={ProjectPermissionSub.Member}
renderTooltip
allowedLabel="Edit role"
allowedLabel="Remove from project"
>
{(isAllowed) => (
<Button

View File

@@ -1,6 +1,6 @@
import { faFolder, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format,formatDistance } from "date-fns";
import { format, formatDistance } from "date-fns";
import { AnimatePresence, motion } from "framer-motion";
import { twMerge } from "tailwind-merge";
@@ -19,7 +19,8 @@ import {
Th,
THead,
Tooltip,
Tr} from "@app/components/v2";
Tr
} from "@app/components/v2";
import {
ProjectPermissionActions,
ProjectPermissionSub,
@@ -104,7 +105,7 @@ export const MemberProjectAdditionalPrivilegeSection = ({ membershipDetails }: P
>
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100">
Project Additional Privilege
Project Additional Privileges
</h3>
{userId !== membershipDetails?.user?.id &&
membershipDetails?.status !== "invited" && (
@@ -180,7 +181,7 @@ export const MemberProjectAdditionalPrivilegeSection = ({ membershipDetails }: P
}}
onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)}
>
<Td className="capitalize">{privilegeDetails.slug}</Td>
<Td>{privilegeDetails.slug}</Td>
<Td>
<Tooltip asChild={false} content={toolTipText}>
<Tag

View File

@@ -163,7 +163,7 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({
onGoBack();
} catch (err) {
console.log(err);
createNotification({ type: "error", text: "Failed to update role" });
createNotification({ type: "error", text: "Failed to update privilege" });
}
};

View File

@@ -20,7 +20,8 @@ import {
Th,
THead,
Tooltip,
Tr} from "@app/components/v2";
Tr
} from "@app/components/v2";
import {
ProjectPermissionActions,
ProjectPermissionSub,
@@ -81,7 +82,7 @@ export const MemberRoleDetailsSection = ({
I={ProjectPermissionActions.Edit}
a={ProjectPermissionSub.Member}
renderTooltip
allowedLabel="Edit role"
allowedLabel="Edit role(s)"
>
{(isAllowed) => (
<IconButton

View File

@@ -19,16 +19,19 @@ export const IdentityRoleForm = ({ identityProjectMember, onOpenUpgradeModal }:
identityProjectMember={identityProjectMember}
onOpenUpgradeModal={onOpenUpgradeModal}
/>
<Alert className="mt-4">
<Alert
title="Additional privileges have been moved and now offer full permission customization."
className="mt-4 border-primary/50 bg-primary/10"
>
<AlertDescription>
Additional privileges now offer full permissions and have been moved to a new screen.
<br />
<Link
href={`/project/${currentWorkspace?.id || ""}/identitiesq/${
href={`/project/${currentWorkspace?.id || ""}/identities/${
identityProjectMember?.identity?.id
}`}
>
<span className="cursor-pointer text-primary">Click here to access them.</span>
<span className="cursor-pointer text-primary underline underline-offset-2">
Click here to access them now
</span>
</Link>
</AlertDescription>
</Alert>

View File

@@ -15,12 +15,15 @@ export const MemberRoleForm = ({ projectMember, onOpenUpgradeModal }: Props) =>
return (
<div>
<MemberRbacSection projectMember={projectMember} onOpenUpgradeModal={onOpenUpgradeModal} />
<Alert className="mt-4">
<Alert
title="Additional privileges have been moved and now offer full permission customization."
className="mt-4 border-primary/50 bg-primary/10"
>
<AlertDescription>
Additional privileges now offer full permissions and have been moved to a new screen.
<br />
<Link href={`/project/${currentWorkspace?.id || ""}/members/${projectMember?.id}`}>
<span className="cursor-pointer text-primary">Click here to access them.</span>
<span className="cursor-pointer text-primary underline underline-offset-2">
Click here to access them now
</span>
</Link>
</AlertDescription>
</Alert>