mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
fixing delete
This commit is contained in:
parent
cdcc546bd7
commit
a1432788cd
3 changed files with 231 additions and 60 deletions
80
src/app/api/portfolio/[portfolioId]/permissions/route.ts
Normal file
80
src/app/api/portfolio/[portfolioId]/permissions/route.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { db } from "@/app/db/db";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { portfolioUsers } from "@/app/db/schema/portfolio";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
|
||||
const PermissionsBodySchema = z.object({
|
||||
userId: z.string(),
|
||||
action: z.enum(["delete", "update"]),
|
||||
});
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
// This endpoint lives at portfolio/{portfolioId}/permissions and will return the permissions level for a given portfolio
|
||||
// Call this endpoint with a) userId, b) portfolioId, c) an action and this api will tell you if that person can do that thing
|
||||
|
||||
const body = await request.json();
|
||||
let validatedBody;
|
||||
|
||||
try {
|
||||
validatedBody = PermissionsBodySchema.parse(body);
|
||||
} catch (error) {
|
||||
console.error("Invalid input: ", error);
|
||||
return new NextResponse(JSON.stringify({ msg: "Invalid input" }), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const action = validatedBody.action;
|
||||
const userId = validatedBody.userId;
|
||||
const portfolioId = params.portfolioId;
|
||||
|
||||
const existingPortfolioPermissions = await db.query.portfolioUsers.findFirst({
|
||||
where: and(
|
||||
eq(portfolioUsers.portfolioId, BigInt(portfolioId)),
|
||||
eq(portfolioUsers.userId, BigInt(userId))
|
||||
),
|
||||
});
|
||||
|
||||
if (!existingPortfolioPermissions) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Portfolio not found or unauthorized" }),
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const role = existingPortfolioPermissions.role;
|
||||
|
||||
let permitted;
|
||||
|
||||
// If the action is a delete, we only allow an admin or creator to delete
|
||||
if (action === "delete") {
|
||||
if (role === "admin" || role === "creator") {
|
||||
permitted = true;
|
||||
} else {
|
||||
permitted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the action is an update, we allow an individual admin, creator or write role to update
|
||||
if (action === "update") {
|
||||
if (role === "admin" || role === "creator" || role === "write") {
|
||||
permitted = true;
|
||||
} else {
|
||||
permitted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returning a successful response
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
permitted: permitted,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,24 +1,37 @@
|
|||
import { db } from "@/app/db/db";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { portfolio, portfolioUsers } from "@/app/db/schema/portfolio";
|
||||
import { and, eq, inArray } from "drizzle-orm";
|
||||
import { user } from "@/app/db/schema/users";
|
||||
import {
|
||||
recommendation,
|
||||
recommendationMaterials,
|
||||
planRecommendations,
|
||||
plan,
|
||||
scenario,
|
||||
} from "@/app/db/schema/recommendations";
|
||||
import {
|
||||
propertyTargets,
|
||||
propertyDetailsEpc,
|
||||
property,
|
||||
} from "@/app/db/schema/property";
|
||||
import { eq, inArray } from "drizzle-orm";
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
export async function PUT(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
const body = await request.json();
|
||||
console.log("HI WE MADE IT!!");
|
||||
console.log(body);
|
||||
const portfolioId = params.portfolioId;
|
||||
|
||||
const portfolioId = body.portfolioId;
|
||||
// We'll eventually veryify the user is authorized to update this portfolio
|
||||
const userId = body.userId;
|
||||
|
||||
delete body.userId;
|
||||
delete body.portfolioId;
|
||||
|
||||
console.log(body);
|
||||
|
||||
// Update the database
|
||||
await db.update(portfolio).set(body).where(eq(portfolio.id, portfolioId));
|
||||
await db
|
||||
.update(portfolio)
|
||||
.set(body)
|
||||
.where(eq(portfolio.id, BigInt(portfolioId)));
|
||||
|
||||
// Returning a successful response
|
||||
return new NextResponse(JSON.stringify({}), {
|
||||
|
|
@ -26,46 +39,110 @@ export async function PUT(request: NextRequest) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function DELETE(request: NextRequest) {
|
||||
console.log("Incoming DELETE request:", request.method);
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
try {
|
||||
// Parse the request body
|
||||
const body = await request.json();
|
||||
console.log("DELETE Request Received", body);
|
||||
const portfolioId = params.portfolioId;
|
||||
|
||||
const portfolioId = body.portfolioId;
|
||||
const userId = body.userId;
|
||||
// 1) Fetch the portfolio ids
|
||||
// 2) Fetch the recommendation ids
|
||||
// 3) Delete all entries from RecommendationMaterials for these recommendations
|
||||
// 4) Delete all entries from PlanRecommendations that reference plans in the portfolio
|
||||
// 5) Delete all Plans associated with the portfolio
|
||||
// 6) Delete all Scenarios associated with the portfolio
|
||||
// 7) Delete all Recommendations associated with the properties
|
||||
// 8) Delete PropertyTargetsModel, PropertyDetailsEpcModel, and PropertyModel
|
||||
// 9) Delete portfolioUsers
|
||||
// 10) Then, we finally delete the portfolio!!!
|
||||
|
||||
// First verify the portfolio exists and belongs to this user
|
||||
const existingPortfolio = await db.query.portfolio.findFirst({
|
||||
where: and(
|
||||
eq(portfolioUsers.portfolioId, portfolioId),
|
||||
eq(portfolioUsers.userId, userId)
|
||||
)
|
||||
// Step 1) Fetch the property ids for the portfolio
|
||||
const propertyIdsResponse = await db.query.property.findMany({
|
||||
columns: { id: true },
|
||||
where: eq(property.portfolioId, BigInt(portfolioId)),
|
||||
});
|
||||
const propertyIds = propertyIdsResponse.map((property) => property.id);
|
||||
|
||||
if (!existingPortfolio) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Portfolio not found or unauthorized" }),
|
||||
{ status: 404 }
|
||||
// Step 2) Fetch the recommendation ids - filter the recommendation table, where propertyId is in the propertyIds
|
||||
// if there are no prpoperty Ids, we make recommendationIds an empty array
|
||||
let recommendationIds: bigint[] = [];
|
||||
if (propertyIds.length) {
|
||||
const recommendations = await db.query.recommendation.findMany({
|
||||
columns: { id: true },
|
||||
where: inArray(recommendation.propertyId, propertyIds),
|
||||
});
|
||||
recommendationIds = recommendations.map(
|
||||
(recommendation) => recommendation.id
|
||||
);
|
||||
}
|
||||
|
||||
// Delete the portfolio
|
||||
// Step 3) Delete all entries from RecommendationMaterials for these recommendations
|
||||
if (recommendationIds.length) {
|
||||
await db
|
||||
.delete(recommendationMaterials)
|
||||
.where(
|
||||
inArray(recommendationMaterials.recommendationId, recommendationIds)
|
||||
);
|
||||
}
|
||||
|
||||
// Step 4) Delete all entries from PlanRecommendations that reference plans in the portfolio
|
||||
// Get the plan ids
|
||||
const plans = await db.query.plan.findMany({
|
||||
columns: { id: true },
|
||||
where: eq(plan.portfolioId, BigInt(portfolioId)),
|
||||
});
|
||||
const planIds = plans.map((plan) => plan.id);
|
||||
|
||||
if (planIds.length) {
|
||||
await db
|
||||
.delete(planRecommendations)
|
||||
.where(inArray(planRecommendations.planId, planIds));
|
||||
}
|
||||
|
||||
// Step 5) Delete all Plans associated with the portfolio
|
||||
await db.delete(plan).where(eq(plan.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
// Step 6) Delete all Scenarios associated with the portfolio
|
||||
await db
|
||||
.delete(portfolio)
|
||||
.where(eq(portfolio.id, portfolioId));
|
||||
.delete(scenario)
|
||||
.where(eq(scenario.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
// Step 7) Delete all Recommendations associated with the properties
|
||||
if (propertyIds.length) {
|
||||
await db
|
||||
.delete(recommendation)
|
||||
.where(inArray(recommendation.propertyId, propertyIds));
|
||||
}
|
||||
|
||||
// Step 8) Delete PropertyTargets, PropertyDetailsEpc, and Property
|
||||
await db
|
||||
.delete(propertyTargets)
|
||||
.where(eq(propertyTargets.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
await db
|
||||
.delete(propertyDetailsEpc)
|
||||
.where(eq(propertyDetailsEpc.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
await db
|
||||
.delete(property)
|
||||
.where(eq(property.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
await db
|
||||
.delete(portfolioUsers)
|
||||
.where(eq(portfolioUsers.portfolioId, BigInt(portfolioId)));
|
||||
|
||||
await db.delete(portfolio).where(eq(portfolio.id, BigInt(portfolioId)));
|
||||
|
||||
// Return success response
|
||||
return new NextResponse(
|
||||
JSON.stringify({ message: "Portfolio successfully deleted" }),
|
||||
JSON.stringify({ message: "Portfolio successfully deleted" }),
|
||||
{ status: 200 }
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error deleting portfolio:", error);
|
||||
return new NextResponse(
|
||||
JSON.stringify({ error: "Your API has Failed to delete the portfolio" }),
|
||||
JSON.stringify({ error: "Your API has Failed to delete the portfolio" }),
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ type updateSettingsArgs = {
|
|||
|
||||
type bodyType = {
|
||||
userId: string;
|
||||
portfolioId: string;
|
||||
name?: string;
|
||||
budget?: number | string;
|
||||
goal?: string;
|
||||
|
|
@ -92,7 +91,6 @@ const updateSettings = async ({
|
|||
|
||||
const body: bodyType = {
|
||||
userId: userId.toString(),
|
||||
portfolioId: portfolioId,
|
||||
};
|
||||
|
||||
if (name) {
|
||||
|
|
@ -128,25 +126,53 @@ const updateSettings = async ({
|
|||
return response.json();
|
||||
};
|
||||
|
||||
async function deletePortfolio({ userId, portfolioId }: {
|
||||
async function deletePortfolio({
|
||||
userId,
|
||||
portfolioId,
|
||||
}: {
|
||||
userId: bigint;
|
||||
portfolioId: string;
|
||||
}) {
|
||||
try {
|
||||
console.log("Attempting to DELETE portfolio by calling API:", { userId, portfolioId });
|
||||
console.log("Attempting to DELETE portfolio by calling API:", {
|
||||
userId,
|
||||
portfolioId,
|
||||
});
|
||||
|
||||
// We'll check if the user is authorized to delete this portfolio
|
||||
const permissionsReponse = await fetch(
|
||||
`/api/portfolio/${portfolioId}/permissions`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: userId.toString(),
|
||||
action: "delete",
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const permissionsData = await permissionsReponse.json();
|
||||
const permitted = permissionsData.permitted;
|
||||
|
||||
// If the user is not permitted to delete the portfolio, we'll throw an error
|
||||
if (!permitted) {
|
||||
throw new Error("User is not permitted to delete this portfolio");
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/portfolio/${portfolioId}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
userId: userId.toString(),
|
||||
portfolioId: portfolioId,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("deletePortfolio has been called into action but utterly failed to do the API handoff");
|
||||
throw new Error(
|
||||
"deletePortfolio has been called into action but utterly failed to do the API handoff"
|
||||
);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
|
|
@ -165,7 +191,6 @@ export default function PortfolioSettings({
|
|||
}) {
|
||||
// This is a client component so we can access the session directly
|
||||
const session = useSession();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const { mutate, isLoading } = useMutation(updateSettings, {
|
||||
|
|
@ -181,11 +206,13 @@ export default function PortfolioSettings({
|
|||
const { mutate: mutateDelete } = useMutation(deletePortfolio, {
|
||||
onSuccess: () => {
|
||||
setIsDeleteModalOpen(false);
|
||||
console.log("Succesfully Deleted")
|
||||
router.push('/home');
|
||||
router.push("/home");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("Because the API hand off failed, we're right back here at the mutation station", error);
|
||||
console.error(
|
||||
"Because the API hand off failed, we're right back here at the mutation station",
|
||||
error
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -230,7 +257,7 @@ export default function PortfolioSettings({
|
|||
userId,
|
||||
portfolioId,
|
||||
});
|
||||
console.log("succesfully called the mututate function")
|
||||
console.log("succesfully called the mututate function");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -303,19 +330,6 @@ export default function PortfolioSettings({
|
|||
status: portfolioStatus,
|
||||
});
|
||||
}
|
||||
|
||||
// Delete function
|
||||
|
||||
function handleDelete() {
|
||||
mutate({
|
||||
userId,
|
||||
portfolioId,
|
||||
name: portfolioName,
|
||||
budget: portfolioBudget,
|
||||
goal: portfolioGoal,
|
||||
status: portfolioStatus,
|
||||
});
|
||||
}
|
||||
|
||||
// HTML to render the page
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue