mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-22 08:45:24 +00:00
✨ create policy endpoitn
This commit is contained in:
@@ -637,6 +637,10 @@
|
|||||||
"rulesNoOne": "No rules. Add a rule using the form.",
|
"rulesNoOne": "No rules. Add a rule using the form.",
|
||||||
"rulesOrder": "Rules are evaluated by priority in ascending order.",
|
"rulesOrder": "Rules are evaluated by priority in ascending order.",
|
||||||
"rulesSubmit": "Save Rules",
|
"rulesSubmit": "Save Rules",
|
||||||
|
"policyErrorCreate": "Error creating policy",
|
||||||
|
"policyErrorCreateDescription": "An error occurred when creating the policy",
|
||||||
|
"policyErrorCreateMessageDescription": "An unexpected error occurred",
|
||||||
|
"policyCreatedSuccess": "Resource policy succesfully created",
|
||||||
"resourceErrorCreate": "Error creating resource",
|
"resourceErrorCreate": "Error creating resource",
|
||||||
"resourceErrorCreateDescription": "An error occurred when creating the resource",
|
"resourceErrorCreateDescription": "An error occurred when creating the resource",
|
||||||
"resourceErrorCreateMessage": "Error creating resource:",
|
"resourceErrorCreateMessage": "Error creating resource:",
|
||||||
|
|||||||
@@ -133,13 +133,13 @@ export enum ActionsEnum {
|
|||||||
listApprovals = "listApprovals",
|
listApprovals = "listApprovals",
|
||||||
updateApprovals = "updateApprovals",
|
updateApprovals = "updateApprovals",
|
||||||
listResourcePolicies = "listResourcePolicies",
|
listResourcePolicies = "listResourcePolicies",
|
||||||
createResourcePolicies = "createResourcePolicies",
|
createResourcePolicy = "createResourcePolicy",
|
||||||
updateResourcePolicies = "updateResourcePolicies",
|
updateResourcePolicy = "updateResourcePolicy",
|
||||||
deleteResourcePolicies = "deleteResourcePolicies",
|
deleteResourcePolicy = "deleteResourcePolicy",
|
||||||
listResourcePolicyRoles = "listResourcePolicyRoles",
|
listResourcePolicyRoles = "listResourcePolicyRoles",
|
||||||
setResourcePolicyRoles = "setResourcePolicyRoles",
|
setResourcePolicyRoles = "setResourcePolicyRoles",
|
||||||
listResourcePolicyUsers = "listResourcePolicyUsers",
|
listResourcePolicyUsers = "listResourcePolicyUsers",
|
||||||
setResourcePolicyUsers = "setResourcePolicyUsers",
|
setResourcePolicyUsers = "setResourcePolicyUsers"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUserActionPermission(
|
export async function checkUserActionPermission(
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { clients, db, resources, siteResources } from "@server/db";
|
import {
|
||||||
|
clients,
|
||||||
|
db,
|
||||||
|
resourcePolicies,
|
||||||
|
resources,
|
||||||
|
siteResources
|
||||||
|
} from "@server/db";
|
||||||
import { randomInt } from "crypto";
|
import { randomInt } from "crypto";
|
||||||
import { exitNodes, sites } from "@server/db";
|
import { exitNodes, sites } from "@server/db";
|
||||||
import { eq, and } from "drizzle-orm";
|
import { eq, and } from "drizzle-orm";
|
||||||
@@ -107,6 +113,35 @@ export async function getUniqueResourceName(orgId: string): Promise<string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getUniqueResourcePolicyName(
|
||||||
|
orgId: string
|
||||||
|
): Promise<string> {
|
||||||
|
let loops = 0;
|
||||||
|
while (true) {
|
||||||
|
if (loops > 100) {
|
||||||
|
throw new Error("Could not generate a unique name");
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = generateName();
|
||||||
|
const policyCount = await db
|
||||||
|
.select({
|
||||||
|
niceId: resourcePolicies.niceId,
|
||||||
|
orgId: resourcePolicies.orgId
|
||||||
|
})
|
||||||
|
.from(resourcePolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourcePolicies.niceId, name),
|
||||||
|
eq(resourcePolicies.orgId, orgId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (policyCount.length === 0) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
loops++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getUniqueSiteResourceName(
|
export async function getUniqueSiteResourceName(
|
||||||
orgId: string
|
orgId: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import * as misc from "#private/routers/misc";
|
|||||||
import * as reKey from "#private/routers/re-key";
|
import * as reKey from "#private/routers/re-key";
|
||||||
import * as approval from "#private/routers/approvals";
|
import * as approval from "#private/routers/approvals";
|
||||||
import * as resource from "#private/routers/resource";
|
import * as resource from "#private/routers/resource";
|
||||||
|
import * as policy from "#private/routers/policy";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
verifyOrgAccess,
|
verifyOrgAccess,
|
||||||
@@ -349,9 +350,19 @@ authenticated.get(
|
|||||||
verifyLimits,
|
verifyLimits,
|
||||||
verifyUserHasAction(ActionsEnum.listResourcePolicies),
|
verifyUserHasAction(ActionsEnum.listResourcePolicies),
|
||||||
logActionAudit(ActionsEnum.listResourcePolicies),
|
logActionAudit(ActionsEnum.listResourcePolicies),
|
||||||
resource.listResourcePolicies
|
policy.listResourcePolicies
|
||||||
);
|
);
|
||||||
|
|
||||||
|
authenticated.post(
|
||||||
|
"/org/:orgId/resource-policy",
|
||||||
|
verifyValidLicense,
|
||||||
|
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
|
||||||
|
verifyOrgAccess,
|
||||||
|
verifyLimits,
|
||||||
|
verifyUserHasAction(ActionsEnum.createResourcePolicy),
|
||||||
|
logActionAudit(ActionsEnum.createResourcePolicy),
|
||||||
|
policy.createResourcePolicy
|
||||||
|
);
|
||||||
|
|
||||||
authenticated.put(
|
authenticated.put(
|
||||||
"/org/:orgId/approvals/:approvalId",
|
"/org/:orgId/approvals/:approvalId",
|
||||||
|
|||||||
178
server/private/routers/policy/createResourcePolicy.ts
Normal file
178
server/private/routers/policy/createResourcePolicy.ts
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
import z from "zod";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
import {
|
||||||
|
db,
|
||||||
|
orgs,
|
||||||
|
resourcePolicies,
|
||||||
|
rolePolicies,
|
||||||
|
roles,
|
||||||
|
userPolicies,
|
||||||
|
type ResourcePolicy
|
||||||
|
} from "@server/db";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||||
|
import response from "@server/lib/response";
|
||||||
|
|
||||||
|
const createResourcePolicyParamsSchema = z.strictObject({
|
||||||
|
orgId: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
const createResourcePolicyBodySchema = z.strictObject({
|
||||||
|
name: z.string().min(1).max(255),
|
||||||
|
sso: z.boolean(),
|
||||||
|
skipToIdpId: z.string().optional(),
|
||||||
|
roleIds: z.array(z.string()).optional().default([]),
|
||||||
|
userIds: z.array(z.string()).optional().default([])
|
||||||
|
});
|
||||||
|
|
||||||
|
registry.registerPath({
|
||||||
|
method: "post",
|
||||||
|
path: "/org/{orgId}/resource-policy",
|
||||||
|
description: "Create a resource.",
|
||||||
|
tags: [OpenAPITags.Org, OpenAPITags.Resource],
|
||||||
|
request: {
|
||||||
|
params: createResourcePolicyParamsSchema,
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: createResourcePolicyParamsSchema
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function createResourcePolicy(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// Validate request params
|
||||||
|
const parsedParams = createResourcePolicyParamsSchema.safeParse(
|
||||||
|
req.params
|
||||||
|
);
|
||||||
|
if (!parsedParams.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedParams.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const { orgId } = parsedParams.data;
|
||||||
|
|
||||||
|
if (req.user && !req.userOrgRoleId) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the org
|
||||||
|
const org = await db
|
||||||
|
.select()
|
||||||
|
.from(orgs)
|
||||||
|
.where(eq(orgs.orgId, orgId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (org.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Organization with ID ${orgId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedBody = createResourcePolicyBodySchema.safeParse(req.body);
|
||||||
|
if (!parsedBody.success) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
fromError(parsedBody.error).toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, sso, userIds, roleIds, skipToIdpId } = parsedBody.data;
|
||||||
|
|
||||||
|
const isAuthEnabeld = sso; // other conditions will follow
|
||||||
|
|
||||||
|
if (!isAuthEnabeld) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
"At least one authentication policy must be set: platform SSO, an authentication method, one-time password, or a rule."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminRole = await db
|
||||||
|
.select()
|
||||||
|
.from(roles)
|
||||||
|
.where(and(eq(roles.isAdmin, true), eq(roles.orgId, orgId)))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (adminRole.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, `Admin role not found`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const niceId = await getUniqueResourcePolicyName(orgId);
|
||||||
|
|
||||||
|
const policy = await db.transaction(async (trx) => {
|
||||||
|
const [newPolicy] = await trx
|
||||||
|
.insert(resourcePolicies)
|
||||||
|
.values({
|
||||||
|
niceId,
|
||||||
|
orgId,
|
||||||
|
name,
|
||||||
|
sso
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
await trx.insert(rolePolicies).values({
|
||||||
|
roleId: adminRole[0].roleId,
|
||||||
|
resourcePolicyId: newPolicy.resourcePolicyId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.user && req.userOrgRoleId != adminRole[0].roleId) {
|
||||||
|
// make sure the user can access the policy
|
||||||
|
await trx.insert(userPolicies).values({
|
||||||
|
userId: req.user?.userId!,
|
||||||
|
resourcePolicyId: newPolicy.resourcePolicyId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPolicy;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!policy) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
"Failed to create policy"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return response<ResourcePolicy>(res, {
|
||||||
|
data: policy,
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "resource policy created successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
server/private/routers/policy/index.ts
Normal file
15
server/private/routers/policy/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of a proprietary work.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Fossorial, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is licensed under the Fossorial Commercial License.
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||||
|
*
|
||||||
|
* This file is not licensed under the AGPLv3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from "./createResourcePolicy";
|
||||||
|
export * from "./listResourcePolicies";
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
|
||||||
import z from "zod";
|
|
||||||
|
|
||||||
const createResourcePolicyParamsSchema = z.strictObject({
|
|
||||||
orgId: z.string()
|
|
||||||
});
|
|
||||||
|
|
||||||
export async function createResourcePolicy(
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: NextFunction
|
|
||||||
) {}
|
|
||||||
@@ -12,5 +12,3 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from "./getMaintenanceInfo";
|
export * from "./getMaintenanceInfo";
|
||||||
export * from "./listResourcePolicies";
|
|
||||||
export * from "./createResourcePolicy";
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||||
import { z } from "zod";
|
import { build } from "@server/build";
|
||||||
import { db, loginPage } from "@server/db";
|
|
||||||
import {
|
import {
|
||||||
domains,
|
db,
|
||||||
orgDomains,
|
loginPage,
|
||||||
orgs,
|
orgs,
|
||||||
Resource,
|
Resource,
|
||||||
resources,
|
resources,
|
||||||
@@ -11,19 +10,19 @@ import {
|
|||||||
roles,
|
roles,
|
||||||
userResources
|
userResources
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import response from "@server/lib/response";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import { eq, and } from "drizzle-orm";
|
|
||||||
import { fromError } from "zod-validation-error";
|
|
||||||
import logger from "@server/logger";
|
|
||||||
import { subdomainSchema } from "@server/lib/schemas";
|
|
||||||
import config from "@server/lib/config";
|
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
|
||||||
import { build } from "@server/build";
|
|
||||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
|
||||||
import { getUniqueResourceName } from "@server/db/names";
|
import { getUniqueResourceName } from "@server/db/names";
|
||||||
|
import config from "@server/lib/config";
|
||||||
import { validateAndConstructDomain } from "@server/lib/domainUtils";
|
import { validateAndConstructDomain } from "@server/lib/domainUtils";
|
||||||
|
import response from "@server/lib/response";
|
||||||
|
import { subdomainSchema } from "@server/lib/schemas";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { fromError } from "zod-validation-error";
|
||||||
|
|
||||||
const createResourceParamsSchema = z.strictObject({
|
const createResourceParamsSchema = z.strictObject({
|
||||||
orgId: z.string()
|
orgId: z.string()
|
||||||
@@ -298,7 +297,7 @@ async function createHttpResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (build != "oss") {
|
if (build !== "oss") {
|
||||||
await createCertificate(domainId, fullDomain, db);
|
await createCertificate(domainId, fullDomain, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,14 @@ import { toast } from "@app/hooks/useToast";
|
|||||||
import { createApiClient } from "@app/lib/api";
|
import { createApiClient } from "@app/lib/api";
|
||||||
import type { ListResourcePoliciesResponse } from "@server/routers/resource/types";
|
import type { ListResourcePoliciesResponse } from "@server/routers/resource/types";
|
||||||
import type { PaginationState } from "@tanstack/react-table";
|
import type { PaginationState } from "@tanstack/react-table";
|
||||||
|
import { ArrowRight, MoreHorizontal } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useTransition } from "react";
|
import { useTransition } from "react";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||||
import type { ExtendedColumnDef } from "./ui/data-table";
|
import type { ExtendedColumnDef } from "./ui/data-table";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -15,12 +20,6 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger
|
DropdownMenuTrigger
|
||||||
} from "./ui/dropdown-menu";
|
} from "./ui/dropdown-menu";
|
||||||
import { Button } from "./ui/button";
|
|
||||||
import { MoreHorizontal, ArrowRight } from "lucide-react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import { Badge } from "./ui/badge";
|
|
||||||
|
|
||||||
type ResourcePolicyRow = ListResourcePoliciesResponse["policies"][number];
|
type ResourcePolicyRow = ListResourcePoliciesResponse["policies"][number];
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ import {
|
|||||||
PolicyUsersRolesSection
|
PolicyUsersRolesSection
|
||||||
} from "./ResourcePolicySubForms";
|
} from "./ResourcePolicySubForms";
|
||||||
import { type PolicyFormValues, createPolicySchema } from ".";
|
import { type PolicyFormValues, createPolicySchema } from ".";
|
||||||
|
import { toast } from "@app/hooks/useToast";
|
||||||
|
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||||
|
import { orgs, type ResourcePolicy } from "@server/db";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
// ─── CreatePolicyForm ─────────────────────────────────────────────────────────
|
// ─── CreatePolicyForm ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -51,9 +56,12 @@ export function CreatePolicyForm({}: CreatePolicyFormProps) {
|
|||||||
const { org } = useOrgContext();
|
const { org } = useOrgContext();
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
|
const api = createApiClient({ env });
|
||||||
const [, formAction, isSubmitting] = useActionState(onSubmit, null);
|
const [, formAction, isSubmitting] = useActionState(onSubmit, null);
|
||||||
const { isPaidUser } = usePaidStatus();
|
const { isPaidUser } = usePaidStatus();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const isMaxmindAvailable = !!(
|
const isMaxmindAvailable = !!(
|
||||||
env.server.maxmind_db_path && env.server.maxmind_db_path.length > 0
|
env.server.maxmind_db_path && env.server.maxmind_db_path.length > 0
|
||||||
);
|
);
|
||||||
@@ -96,6 +104,52 @@ export function CreatePolicyForm({}: CreatePolicyFormProps) {
|
|||||||
const isValid = await form.trigger();
|
const isValid = await form.trigger();
|
||||||
|
|
||||||
if (!isValid) return;
|
if (!isValid) return;
|
||||||
|
|
||||||
|
const payload = form.getValues();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await api
|
||||||
|
.post<AxiosResponse<ResourcePolicy>>(
|
||||||
|
`/org/${org.org.orgId}/resource-policy/`,
|
||||||
|
{
|
||||||
|
name: payload.name,
|
||||||
|
sso: payload.sso,
|
||||||
|
roleIds: payload.roles.map((r) => r.id),
|
||||||
|
userIds: payload.users.map((u) => u.id)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: t("policyErrorCreate"),
|
||||||
|
description: formatAxiosError(
|
||||||
|
e,
|
||||||
|
t("policyErrorCreateDescription")
|
||||||
|
)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.status === 201) {
|
||||||
|
const id = res.data.data.resourcePolicyId;
|
||||||
|
const niceId = res.data.data.niceId;
|
||||||
|
|
||||||
|
router.push(`/${org.org.orgId}/settings/policies/resources/`);
|
||||||
|
// should redirect to the details page
|
||||||
|
// router.push(
|
||||||
|
// `/${org.org.orgId}/settings/policies/resources/${niceId}`
|
||||||
|
// );
|
||||||
|
toast({
|
||||||
|
title: t("success"),
|
||||||
|
description: t("policyCreatedSuccess")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: t("policyErrorCreate"),
|
||||||
|
description: t("policyErrorCreateMessageDescription")
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const allRoles = useMemo(
|
const allRoles = useMemo(
|
||||||
|
|||||||
Reference in New Issue
Block a user