// routes/api/update/tenant_application.ts import { define } from "../../../utils.ts"; import { getApplicationById, getTenantApplicationsByLandlord, updateApplicationStatus, } from "../../../services/tenantApplicationService.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, user_type } = stateData; const contentType = ctx.req.headers.get("content-type") || ""; let data: Record = {}; let sender: string | null = null; let isJsonRequest = false; // Handle both JSON and form data if (contentType.includes("application/json")) { isJsonRequest = true; const jsonData = await ctx.req.json(); data = jsonData; } else { const formData = await ctx.req.formData(); sender = formData.get("sender")?.toString() || null; data = { id: formData.get("id")?.toString() || "", status: formData.get("status")?.toString() || "", reviewed_on: parseInt( formData.get("reviewed_on")?.toString() || Date.now().toString(), ), }; } const id = data.id as string; const status = data.status as string; const reviewed_on = data.reviewed_on as number; if (!id || !status) { return new Response( JSON.stringify({ error: "Application ID and status are required", }), { status: 400, headers: { "Content-Type": "application/json" }, }, ); } if (!["approved", "rejected"].includes(status)) { return new Response( JSON.stringify({ error: "Status must be 'approved' or 'rejected'", }), { status: 400, headers: { "Content-Type": "application/json" }, }, ); } // DATA ISOLATION: Verify user has authorization to update this application // Only landlords who own the property can approve/reject applications if (user_type === "landlord" || user_type === "admin") { const application = await getApplicationById(id); if (!application) { return new Response( JSON.stringify({ error: "Application not found", }), { status: 404, headers: { "Content-Type": "application/json" }, }, ); } // Check if this landlord owns the property for this application const landlordApplications = await getTenantApplicationsByLandlord( user_id, ); const hasAccess = landlordApplications.some((app) => app.id === id); if (!hasAccess) { return new Response( JSON.stringify({ error: "Application not found or unauthorized", }), { status: 403, headers: { "Content-Type": "application/json" }, }, ); } } else { // Tenants cannot approve/reject applications return new Response( JSON.stringify({ error: "Unauthorized to update application status", }), { status: 403, headers: { "Content-Type": "application/json" }, }, ); } const result = await updateApplicationStatus( id, status as "approved" | "rejected", reviewed_on, ); // Return appropriate response based on request type if (isJsonRequest) { return new Response( JSON.stringify({ success: true, application: result[0], }), { status: 200, headers: { "Content-Type": "application/json" }, }, ); } else { // Redirect back to the sender URL 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) { return new Response(JSON.stringify({ error: e }), { status: 500, headers: { "Content-Type": "application/json" }, }); } }, });