mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-28 15:56:39 +00:00
support delete org and preserve path on switch
This commit is contained in:
@@ -86,16 +86,14 @@ authenticated.post(
|
|||||||
org.updateOrg
|
org.updateOrg
|
||||||
);
|
);
|
||||||
|
|
||||||
if (build !== "saas") {
|
authenticated.delete(
|
||||||
authenticated.delete(
|
"/org/:orgId",
|
||||||
"/org/:orgId",
|
verifyOrgAccess,
|
||||||
verifyOrgAccess,
|
verifyUserIsOrgOwner,
|
||||||
verifyUserIsOrgOwner,
|
verifyUserHasAction(ActionsEnum.deleteOrg),
|
||||||
verifyUserHasAction(ActionsEnum.deleteOrg),
|
logActionAudit(ActionsEnum.deleteOrg),
|
||||||
logActionAudit(ActionsEnum.deleteOrg),
|
org.deleteOrg
|
||||||
org.deleteOrg
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticated.put(
|
authenticated.put(
|
||||||
"/org/:orgId/site",
|
"/org/:orgId/site",
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import logger from "@server/logger";
|
|||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
import { deleteOrgById, sendTerminationMessages } from "@server/lib/deleteOrg";
|
import { deleteOrgById, sendTerminationMessages } from "@server/lib/deleteOrg";
|
||||||
|
import { db, userOrgs, orgs } from "@server/db";
|
||||||
|
import { eq, and } from "drizzle-orm";
|
||||||
|
|
||||||
const deleteOrgSchema = z.strictObject({
|
const deleteOrgSchema = z.strictObject({
|
||||||
orgId: z.string()
|
orgId: z.string()
|
||||||
@@ -41,6 +43,48 @@ export async function deleteOrg(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const { orgId } = parsedParams.data;
|
const { orgId } = parsedParams.data;
|
||||||
|
|
||||||
|
const [data] = await db
|
||||||
|
.select()
|
||||||
|
.from(userOrgs)
|
||||||
|
.innerJoin(orgs, eq(userOrgs.orgId, orgs.orgId))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userOrgs.orgId, orgId),
|
||||||
|
eq(userOrgs.userId, req.user!.userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const org = data?.orgs;
|
||||||
|
const userOrg = data?.userOrgs;
|
||||||
|
|
||||||
|
if (!org || !userOrg) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Organization with ID ${orgId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!userOrg.isOwner) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.FORBIDDEN,
|
||||||
|
"Only organization owners can delete the organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (org.isBillingOrg) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
"Cannot delete a primary organization"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await deleteOrgById(orgId);
|
const result = await deleteOrgById(orgId);
|
||||||
sendTerminationMessages(result);
|
sendTerminationMessages(result);
|
||||||
return response(res, {
|
return response(res, {
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
|||||||
import { Button } from "@app/components/ui/button";
|
import { Button } from "@app/components/ui/button";
|
||||||
import { useOrgContext } from "@app/hooks/useOrgContext";
|
import { useOrgContext } from "@app/hooks/useOrgContext";
|
||||||
import { toast } from "@app/hooks/useToast";
|
import { toast } from "@app/hooks/useToast";
|
||||||
import {
|
import { useState, useTransition, useActionState } from "react";
|
||||||
useState,
|
|
||||||
useTransition,
|
|
||||||
useActionState
|
|
||||||
} from "react";
|
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -54,7 +50,7 @@ export default function GeneralPage() {
|
|||||||
return (
|
return (
|
||||||
<SettingsContainer>
|
<SettingsContainer>
|
||||||
<GeneralSectionForm org={org.org} />
|
<GeneralSectionForm org={org.org} />
|
||||||
{build !== "saas" && <DeleteForm org={org.org} />}
|
{!org.org.isBillingOrg && <DeleteForm org={org.org} />}
|
||||||
</SettingsContainer>
|
</SettingsContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { useEnvContext } from "@app/hooks/useEnvContext";
|
|||||||
import { cn } from "@app/lib/cn";
|
import { cn } from "@app/lib/cn";
|
||||||
import { ListUserOrgsResponse } from "@server/routers/org";
|
import { ListUserOrgsResponse } from "@server/routers/org";
|
||||||
import { Check, ChevronsUpDown, Plus, Building2, Users } from "lucide-react";
|
import { Check, ChevronsUpDown, Plus, Building2, Users } from "lucide-react";
|
||||||
import { useRouter } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { useUserContext } from "@app/hooks/useUserContext";
|
import { useUserContext } from "@app/hooks/useUserContext";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -44,6 +44,7 @@ export function OrgSelector({
|
|||||||
const { user } = useUserContext();
|
const { user } = useUserContext();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
@@ -141,7 +142,11 @@ export function OrgSelector({
|
|||||||
key={org.orgId}
|
key={org.orgId}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
router.push(`/${org.orgId}/settings`);
|
const newPath = pathname.replace(
|
||||||
|
/^\/[^/]+/,
|
||||||
|
`/${org.orgId}`
|
||||||
|
);
|
||||||
|
router.push(newPath);
|
||||||
}}
|
}}
|
||||||
className="mx-2 rounded-md"
|
className="mx-2 rounded-md"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user