mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-18 06:51:44 +00:00
✨ apply rules on resource policies
This commit is contained in:
@@ -661,7 +661,7 @@ export const resourceRules = pgTable("resourceRules", {
|
|||||||
value: varchar("value").notNull()
|
value: varchar("value").notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const policyRules = pgTable("policyRules", {
|
export const resourcePolicyRules = pgTable("resourcePolicyRules", {
|
||||||
ruleId: serial("ruleId").primaryKey(),
|
ruleId: serial("ruleId").primaryKey(),
|
||||||
resourcePolicyId: integer("resourcePolicyId")
|
resourcePolicyId: integer("resourcePolicyId")
|
||||||
.notNull()
|
.notNull()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
idp,
|
idp,
|
||||||
|
resourcePolicyRules,
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
resourcePolicyHeaderAuth,
|
resourcePolicyHeaderAuth,
|
||||||
resourcePolicyPassword,
|
resourcePolicyPassword,
|
||||||
@@ -56,6 +57,7 @@ async function query(params: z.infer<typeof getResourcePolicySchema>) {
|
|||||||
.select({
|
.select({
|
||||||
resourcePolicyId: resourcePolicies.resourcePolicyId,
|
resourcePolicyId: resourcePolicies.resourcePolicyId,
|
||||||
sso: resourcePolicies.sso,
|
sso: resourcePolicies.sso,
|
||||||
|
applyRules: resourcePolicies.applyRules,
|
||||||
emailWhitelistEnabled: resourcePolicies.emailWhitelistEnabled,
|
emailWhitelistEnabled: resourcePolicies.emailWhitelistEnabled,
|
||||||
idpId: resourcePolicies.idpId,
|
idpId: resourcePolicies.idpId,
|
||||||
niceId: resourcePolicies.niceId,
|
niceId: resourcePolicies.niceId,
|
||||||
@@ -134,11 +136,24 @@ async function query(params: z.infer<typeof getResourcePolicySchema>) {
|
|||||||
eq(resourcePolicyWhiteList.resourcePolicyId, res.resourcePolicyId)
|
eq(resourcePolicyWhiteList.resourcePolicyId, res.resourcePolicyId)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const policyRules = await db
|
||||||
|
.select({
|
||||||
|
ruleId: resourcePolicyRules.ruleId,
|
||||||
|
enabled: resourcePolicyRules.enabled,
|
||||||
|
priority: resourcePolicyRules.priority,
|
||||||
|
action: resourcePolicyRules.action,
|
||||||
|
match: resourcePolicyRules.match,
|
||||||
|
value: resourcePolicyRules.value
|
||||||
|
})
|
||||||
|
.from(resourcePolicyRules)
|
||||||
|
.where(eq(resourcePolicyRules.resourcePolicyId, res.resourcePolicyId));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...res,
|
...res,
|
||||||
roles: policyRoles,
|
roles: policyRoles,
|
||||||
users: policyUsers,
|
users: policyUsers,
|
||||||
emailWhiteList: policyEmailWhiteList
|
emailWhiteList: policyEmailWhiteList,
|
||||||
|
rules: policyRules
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, policyRules, resourcePolicies } from "@server/db";
|
import { db, resourcePolicyRules, resourcePolicies } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -136,11 +136,13 @@ export async function setResourcePolicyRules(
|
|||||||
.where(eq(resourcePolicies.resourcePolicyId, resourcePolicyId));
|
.where(eq(resourcePolicies.resourcePolicyId, resourcePolicyId));
|
||||||
|
|
||||||
await trx
|
await trx
|
||||||
.delete(policyRules)
|
.delete(resourcePolicyRules)
|
||||||
.where(eq(policyRules.resourcePolicyId, resourcePolicyId));
|
.where(
|
||||||
|
eq(resourcePolicyRules.resourcePolicyId, resourcePolicyId)
|
||||||
|
);
|
||||||
|
|
||||||
if (rules.length > 0) {
|
if (rules.length > 0) {
|
||||||
await trx.insert(policyRules).values(
|
await trx.insert(resourcePolicyRules).values(
|
||||||
rules.map((rule) => ({
|
rules.map((rule) => ({
|
||||||
resourcePolicyId,
|
resourcePolicyId,
|
||||||
...rule
|
...rule
|
||||||
|
|||||||
@@ -78,7 +78,12 @@ import {
|
|||||||
import { ArrowUpDown, Check, ChevronsUpDown, Plus } from "lucide-react";
|
import { ArrowUpDown, Check, ChevronsUpDown, Plus } from "lucide-react";
|
||||||
|
|
||||||
import { useCallback, useMemo, useState, useTransition } from "react";
|
import { useCallback, useMemo, useState, useTransition } from "react";
|
||||||
import { UseFormReturn, useForm } from "react-hook-form";
|
import { UseFormReturn, useForm, useWatch } from "react-hook-form";
|
||||||
|
import { useResourcePolicyContext } from "@app/providers/ResourcePolicyProvider";
|
||||||
|
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||||
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
// ─── PolicyRulesSection ───────────────────────────────────────────────────────
|
// ─── PolicyRulesSection ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -111,17 +116,31 @@ export function EditPolicyRulesSectionForm({
|
|||||||
}: PolicyRulesSectionProps) {
|
}: PolicyRulesSectionProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
|
const { policy } = useResourcePolicyContext();
|
||||||
|
const api = createApiClient(useEnvContext());
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: zodResolver(
|
resolver: zodResolver(
|
||||||
createPolicySchema.pick({
|
createPolicySchema.pick({
|
||||||
rules: true,
|
rules: true,
|
||||||
applyRules: true
|
applyRules: true
|
||||||
})
|
})
|
||||||
)
|
),
|
||||||
|
defaultValues: {
|
||||||
|
applyRules: policy.applyRules,
|
||||||
|
rules: policy.rules
|
||||||
|
}
|
||||||
});
|
});
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
|
||||||
const [rules, setRules] = useState<LocalRule[]>([]);
|
const rulesEnabled = useWatch({
|
||||||
const [rulesEnabled, setRulesEnabled] = useState(false);
|
control: form.control,
|
||||||
|
name: "applyRules"
|
||||||
|
});
|
||||||
|
|
||||||
|
const [rules, setRules] = useState<LocalRule[]>(policy.rules);
|
||||||
|
const [isExpanded, setIsExpanded] = useState(rulesEnabled);
|
||||||
|
|
||||||
const [openAddRuleCountrySelect, setOpenAddRuleCountrySelect] =
|
const [openAddRuleCountrySelect, setOpenAddRuleCountrySelect] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const [openAddRuleAsnSelect, setOpenAddRuleAsnSelect] = useState(false);
|
const [openAddRuleAsnSelect, setOpenAddRuleAsnSelect] = useState(false);
|
||||||
@@ -618,6 +637,45 @@ export function EditPolicyRulesSectionForm({
|
|||||||
|
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
|
|
||||||
|
async function saveRules() {
|
||||||
|
const isValid = form.trigger();
|
||||||
|
if (!isValid) return;
|
||||||
|
|
||||||
|
const payload = form.getValues();
|
||||||
|
console.log({ payload });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await api
|
||||||
|
.put<
|
||||||
|
AxiosResponse<{}>
|
||||||
|
>(`/resource-policy/${policy.resourcePolicyId}/rules`, payload)
|
||||||
|
.catch((e) => {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: t("policyErrorUpdate"),
|
||||||
|
description: formatAxiosError(
|
||||||
|
e,
|
||||||
|
t("policyErrorUpdateDescription")
|
||||||
|
)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.status === 200) {
|
||||||
|
toast({
|
||||||
|
title: t("success"),
|
||||||
|
description: t("policyUpdatedSuccess")
|
||||||
|
});
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
toast({
|
||||||
|
variant: "destructive",
|
||||||
|
title: t("policyErrorUpdate"),
|
||||||
|
description: t("policyErrorUpdateMessageDescription")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isExpanded) {
|
if (!isExpanded) {
|
||||||
return (
|
return (
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
@@ -659,9 +717,8 @@ export function EditPolicyRulesSectionForm({
|
|||||||
<SwitchInput
|
<SwitchInput
|
||||||
id="rules-toggle"
|
id="rules-toggle"
|
||||||
label={t("rulesEnable")}
|
label={t("rulesEnable")}
|
||||||
defaultChecked={false}
|
defaultChecked={rulesEnabled}
|
||||||
onCheckedChange={(val) => {
|
onCheckedChange={(val) => {
|
||||||
setRulesEnabled(val);
|
|
||||||
form.setValue("applyRules", val);
|
form.setValue("applyRules", val);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -1075,9 +1132,9 @@ export function EditPolicyRulesSectionForm({
|
|||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
<SettingsSectionFooter>
|
<SettingsSectionFooter>
|
||||||
<Button
|
<Button
|
||||||
// onClick={saveAllSettings}
|
onClick={() => startTransition(() => saveRules())}
|
||||||
// loading={loading}
|
loading={isPending}
|
||||||
// disabled={loading}
|
disabled={isPending}
|
||||||
>
|
>
|
||||||
{t("rulesSave")}
|
{t("rulesSave")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user