mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
force
This commit is contained in:
parent
c802931b5b
commit
a2b7c643d9
3 changed files with 297 additions and 0 deletions
109
.env.local
Normal file
109
.env.local
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
NEXTAUTH_SECRET=df425f28-06ab-47c2-bb78-7e604387d463
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
|
||||
GOOGLE_CLIENT_ID=232063354367-ustovlgtk3cmtvohvd6tdlejnj1qjjj0.apps.googleusercontent.com
|
||||
|
||||
GOOGLE_CLIENT_SECRET=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
|
||||
|
||||
EPC_AUTH_TOKEN=a2Nvbm5rb3dsZXNzYXJAZ21haWwuY29tOjY5MGJiMWM0NmIyOGI5ZDUxYzAxMzQzYzNiZGNlZGJjZDNmODQwMzA=
|
||||
|
||||
|
||||
|
||||
AZURE_AD_B2C_TENANT_NAME=DomnaApp
|
||||
|
||||
AZURE_AD_B2C_CLIENT_ID=f0a1f977-ddc4-4037-b129-a310008ee934
|
||||
|
||||
AZURE_AD_B2C_CLIENT_SECRET=6uh8Q~dmZNqQy3ZxM_Ce33fVSeW24K27R~pYYduD
|
||||
|
||||
AZURE_AD_B2C_PRIMARY_USER_FLOW=B2C_1_signupsignin
|
||||
|
||||
|
||||
|
||||
AZURE_AD_CLIENT_ID=069e75ee-ba54-45ff-ba77-a06f29c0e21c
|
||||
|
||||
AZURE_AD_CLIENT_SECRET=x6D8Q~f2roqrnoP1YuomSGN5CvU0HPtIWqqPPaYW
|
||||
|
||||
AZURE_AD_TENANT_ID=4a85e8bb-8b7f-4bbd-adc2-1448bb6a9810
|
||||
|
||||
|
||||
|
||||
DB_HOST=terraform-20230705170609686900000001.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com
|
||||
|
||||
DB_PORT=5432
|
||||
|
||||
DB_NAME=DevAssessmentModelDB
|
||||
|
||||
DB_USERNAME=DevAddessmentModelDB
|
||||
|
||||
DB_PASSWORD=!}-A=3D%(2Awy[Qx
|
||||
|
||||
|
||||
|
||||
URL=http://localhost:3000
|
||||
|
||||
PRESIGN_AWS_ACCESS_KEY=AKIAU5A36PPNMR2G7ZQO
|
||||
|
||||
PRESIGN_AWS_SECRET_KEY=r6UitDtHAB01ZmgSj1+vezg2x2GMzh1oqwwUmexQ
|
||||
|
||||
RETROFIT_PLAN_INPUT_BUCKET_NAME=retrofit-plan-inputs-dev
|
||||
|
||||
PRESIGN_AWS_REGION=eu-west-2
|
||||
|
||||
|
||||
|
||||
DUE_CONSIDERATIONS_BUCKET=retrofit-due-considerations-dev
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_ACCESS_KEY=AKIAU5A36PPNPNFWLJOY
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_SECRET_KEY=tCDIH8WPeiob9eR+81hBT2Bxbd/JN5rUcQsePumR
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_REGION=eu-west-2
|
||||
|
||||
|
||||
|
||||
ECO_SPREADSHEET_BUCKET=retrofit-eco-spreadsheet-dev
|
||||
ECO_SPREADSHEET_AWS_ACCESS_KEY=AKIAU5A36PPNPTFDQGOJ
|
||||
ECO_SPREADSHEET_AWS_SECRET_KEY=dj7gXLl6xbWuIeVrgwmujla2HMOEUVyiGmrFpZpX
|
||||
ECO_SPREADSHEET_AWS_REGION=eu-west-2
|
||||
|
||||
# Please change using "Jun-te" aws role atm
|
||||
SQS_AWS_REGION=eu-west-2
|
||||
SQS_AWS_ACCESS_KEY_ID=AKIAU5A36PPNK7RXX52V
|
||||
SQS_AWS_SECRET_ACCESS_KEY=KRTjzoGVestZ0ifDwaAVqiPoXXZAvQKAjY5sVBtP
|
||||
|
||||
|
||||
RETROFIT_ENERGY_ASSESSMENTS_BUCKET=retrofit-energy-assessments-dev
|
||||
|
||||
RETROFIT_ENERGY_ASSESSMENTS_AWS_ACCESS_KEY=AKIAU5A36PPNJMZZ3KRW
|
||||
|
||||
RETROFIT_ENERGY_ASSESSMENTS_AWS_SECRET=Pr5uxwh1zOCocKuFDA4DWQX039t0h2mnM7kaxlSt
|
||||
|
||||
|
||||
|
||||
FASTAPI_API_KEY=4QPwbB6hEdUloDVtbBJCUTfGBdBgWwpeavWQ7t5Z
|
||||
|
||||
FASTAPI_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
|
||||
|
||||
DUE_CONSIDERATIONS_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
ECO_SPREADSHEET_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DOCUMENTS_DATABASE_URL=postgresql://postgres:makingwarmhomes@terraform-20250331175522503500000002.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com:5432/surveyDB
|
||||
|
||||
DOCUMENTS_DB_HOST=terraform-20250331175522503500000002.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com
|
||||
|
||||
DOCUMENTS_DB_PORT=5432
|
||||
|
||||
DOCUMENTS_DB_NAME=surveyDB
|
||||
|
||||
DOCUMENTS_DB_USERNAME=postgres
|
||||
|
||||
DOCUMENTS_DB_PASSWORD=makingwarmhomes
|
||||
|
||||
89
src/app/api/upload/presign-get/route.ts
Normal file
89
src/app/api/upload/presign-get/route.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// app/api/presign-get/route.ts
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
createS3Client,
|
||||
presignGetUrl,
|
||||
parseS3Url,
|
||||
} from "@/app/utils/s3";
|
||||
|
||||
// avoid caching the route itself
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const Schema = z.object({
|
||||
// Either a raw S3 key (e.g. "documents/....pdf") OR a full S3 URL
|
||||
path: z.string().min(1, "path is required"),
|
||||
expiresInSeconds: z.coerce.number().int().positive().default(300),
|
||||
contentType: z.string().optional(), // e.g. application/pdf
|
||||
contentDisposition: z.string().optional(), // e.g. "inline" or 'attachment; filename="file.pdf"'
|
||||
});
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const parsed = Schema.parse({
|
||||
path: searchParams.get("path"),
|
||||
expiresInSeconds: searchParams.get("expiresInSeconds") ?? undefined,
|
||||
contentType: searchParams.get("contentType") ?? undefined,
|
||||
contentDisposition: searchParams.get("contentDisposition") ?? undefined,
|
||||
});
|
||||
|
||||
// Default bucket used when `path` is a raw key (not a full URL)
|
||||
const defaultBucket = process.env.RETROFIT_ENERGY_ASSESSMENTS_BUCKET;
|
||||
if (!defaultBucket) {
|
||||
return NextResponse.json(
|
||||
{ msg: "RETROFIT_ENERGY_ASSESSMENTS_BUCKET is not set" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Build S3 client using Retrofit creds
|
||||
const s3 = createS3Client({
|
||||
region: process.env.PRESIGN_AWS_REGION,
|
||||
accessKeyId: process.env.RETROFIT_ENERGY_ASSESSMENTS_AWS_ACCESS_KEY,
|
||||
secretAccessKey: process.env.RETROFIT_ENERGY_ASSESSMENTS_AWS_SECRET,
|
||||
});
|
||||
|
||||
// Accept either a raw key or a full S3 URL
|
||||
let bucket = defaultBucket;
|
||||
let key = parsed.path;
|
||||
|
||||
if (
|
||||
parsed.path.startsWith("http://") ||
|
||||
parsed.path.startsWith("https://") ||
|
||||
parsed.path.startsWith("s3://")
|
||||
) {
|
||||
const fromUrl = parseS3Url(parsed.path);
|
||||
bucket = fromUrl.bucket;
|
||||
key = fromUrl.key;
|
||||
}
|
||||
|
||||
const url = await presignGetUrl(s3, {
|
||||
bucket,
|
||||
key,
|
||||
expiresInSeconds: parsed.expiresInSeconds,
|
||||
responseContentType: parsed.contentType,
|
||||
responseContentDisposition: parsed.contentDisposition ?? "inline",
|
||||
});
|
||||
|
||||
return new NextResponse(JSON.stringify({ url }), {
|
||||
status: 200,
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"cache-control": "no-store, no-cache, must-revalidate",
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (err instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ msg: "Invalid input", issues: err.issues },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ msg: "Internal server error" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type Report = {
|
||||
id: string;
|
||||
s3FileUri?: string;
|
||||
s3JsonUri?: string;
|
||||
s3FileUploadTimestamp: string;
|
||||
};
|
||||
|
||||
export default function ConditionReport({ latestReport }: { latestReport: Report }) {
|
||||
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
||||
const [jsonUrl, setJsonUrl] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
async function fetchPresigned() {
|
||||
if (!latestReport) return;
|
||||
|
||||
if (latestReport.s3FileUri) {
|
||||
const res = await fetch(
|
||||
`/api/upload/presign-get?` +
|
||||
new URLSearchParams({
|
||||
path: latestReport.s3FileUri,
|
||||
contentType: "application/pdf",
|
||||
contentDisposition: "inline",
|
||||
expiresInSeconds: "300",
|
||||
}),
|
||||
{ cache: "no-store" }
|
||||
);
|
||||
const data = await res.json();
|
||||
if (!cancelled) setPdfUrl(data.url ?? null);
|
||||
}
|
||||
|
||||
if (latestReport.s3JsonUri) {
|
||||
const res = await fetch(
|
||||
`/api/upload/presign-get?` +
|
||||
new URLSearchParams({
|
||||
path: latestReport.s3JsonUri,
|
||||
contentType: "application/json",
|
||||
contentDisposition: "inline",
|
||||
expiresInSeconds: "300",
|
||||
}),
|
||||
{ cache: "no-store" }
|
||||
);
|
||||
const data = await res.json();
|
||||
if (!cancelled) setJsonUrl(data.url ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
fetchPresigned();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [latestReport]);
|
||||
|
||||
return (
|
||||
<div className="px-6 py-4 border rounded-md shadow bg-white space-y-2">
|
||||
<p>
|
||||
<span className="font-semibold">Document ID:</span> {latestReport.id}
|
||||
</p>
|
||||
<p>
|
||||
<span className="font-semibold">Uploaded:</span>{" "}
|
||||
{new Date(latestReport.s3FileUploadTimestamp).toLocaleString()}
|
||||
</p>
|
||||
<p>
|
||||
<span className="font-semibold">PDF:</span>{" "}
|
||||
{pdfUrl ? (
|
||||
<a
|
||||
href={pdfUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
View Report
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-gray-500">Not available</span>
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
<span className="font-semibold">JSON:</span>{" "}
|
||||
{jsonUrl ? (
|
||||
<a
|
||||
href={jsonUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 underline"
|
||||
>
|
||||
View JSON
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-gray-500">Not available</span>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue