2026-02-14 02:20:19 +00:00

143 lines
4.0 KiB
TypeScript

// routes/api/create/lease.ts
import { define } from "../../../utils.ts";
import { createLease } from "../../../services/leaseService.ts";
import { getProperty } from "../../../services/propertyService.ts";
import { SessionCookie } from "../../auth/callback.ts";
export const handler = define.handlers({
async POST(ctx) {
try {
const stateData: SessionCookie = ctx.state.data;
const { user_id } = stateData;
// Check authentication
if (!user_id) {
return new Response(
JSON.stringify({
success: false,
error: "Unauthorized: No session found",
}),
{
status: 401,
headers: { "Content-Type": "application/json" },
},
);
}
const form = await ctx.req.formData();
const sender = form.get("sender");
const tenant_id = form.get("tenant_id")?.toString();
const propertyId = form.get("property_id")?.toString() || "";
const title = form.get("title")?.toString() || "";
const rent = Number(form.get("rent"));
const start_date = form.get("start_date")
? Date.parse(form.get("start_date")?.toString() + "T00:00:00")
: null;
const end_date = form.get("end_date")
? Date.parse(form.get("end_date")?.toString() + "T00:00:00")
: null;
const security_deposit = Number(form.get("security_deposit")) || 0;
// Validate required fields
if (!propertyId) {
return new Response(
JSON.stringify({
success: false,
error: "Property ID is required",
}),
{
status: 400,
headers: { "Content-Type": "application/json" },
},
);
}
if (!start_date || !end_date || isNaN(start_date) || isNaN(end_date)) {
return new Response(
JSON.stringify({
success: false,
error: "Valid start and end dates are required",
}),
{
status: 400,
headers: { "Content-Type": "application/json" },
},
);
}
const property = await getProperty(propertyId);
if (property.length !== 1) {
return new Response(
JSON.stringify({
success: false,
error: "Property not found",
}),
{
status: 404,
headers: { "Content-Type": "application/json" },
},
);
}
const owner_id = property[0].owner_id as string;
// OWNERSHIP VALIDATION: Only property owner can create leases
if (owner_id !== user_id) {
return new Response(
JSON.stringify({
success: false,
error: "Forbidden: You do not own this property",
details: {
user_id,
property_owner_id: owner_id,
property_id: propertyId,
},
}),
{
status: 403,
headers: { "Content-Type": "application/json" },
},
);
}
// Create lease with ownership validated
await createLease(
title,
propertyId,
owner_id,
start_date,
end_date,
rent,
security_deposit,
tenant_id,
);
const senderPath = sender?.toString() || "/";
let redirectUrl = senderPath;
try {
if (senderPath.startsWith("/")) {
const url = new URL(ctx.req.url);
redirectUrl = url.origin + senderPath;
}
} catch (_) {
// fallback: just use senderPath
}
return Response.redirect(redirectUrl, 303);
} catch (e) {
console.error("Error creating lease:", e);
return new Response(
JSON.stringify({
success: false,
error: "Internal server error",
details: e instanceof Error ? e.message : String(e),
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
);
}
},
});