Skip to content

Commit 7bdfb9f

Browse files
committed
fix: proxy history audio, order answers, secure recording endpoint
- History tab audio now routes through /api/recording proxy (was raw) - API orders answers by orderIndex for consistent display - Recording proxy validates user access before serving audio - Remove unused lang variable
1 parent 64ec40f commit 7bdfb9f

4 files changed

Lines changed: 35 additions & 5 deletions

File tree

src/app/api/elderly/[id]/assessment/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export async function GET(
2525

2626
const sessions = await prisma.assessmentSession.findMany({
2727
where: { elderlyProfileId: id },
28-
include: { answers: true },
28+
include: { answers: { orderBy: { orderIndex: "asc" } } },
2929
orderBy: { createdAt: "desc" },
3030
take: 30,
3131
});

src/app/api/recording/route.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,43 @@
11
import { NextRequest, NextResponse } from "next/server";
2+
import { getCurrentUser } from "@/lib/auth";
3+
import { prisma } from "@/lib/prisma";
24

35
export async function GET(req: NextRequest) {
4-
const url = req.nextUrl.searchParams.get("url");
6+
const user = await getCurrentUser();
7+
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
58

9+
const url = req.nextUrl.searchParams.get("url");
610
if (!url || !url.includes("twilio.com")) {
711
return NextResponse.json({ error: "Invalid URL" }, { status: 400 });
812
}
913

14+
// Verify the recording belongs to a session the user has access to
15+
const answer = await prisma.assessmentAnswer.findFirst({
16+
where: { recordingUrl: url },
17+
include: {
18+
session: {
19+
include: {
20+
elderlyProfile: {
21+
include: { caregivers: true },
22+
},
23+
},
24+
},
25+
},
26+
});
27+
28+
if (!answer) {
29+
return NextResponse.json({ error: "Recording not found" }, { status: 404 });
30+
}
31+
32+
const profile = answer.session.elderlyProfile;
33+
const hasAccess =
34+
profile.managerId === user.id ||
35+
profile.caregivers.some((c: { userId: string | null }) => c.userId === user.id);
36+
37+
if (!hasAccess) {
38+
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
39+
}
40+
1041
try {
1142
const authHeader = `Basic ${Buffer.from(
1243
`${process.env.TWILIO_ACCOUNT_SID}:${process.env.TWILIO_AUTH_TOKEN}`
@@ -18,7 +49,7 @@ export async function GET(req: NextRequest) {
1849
});
1950

2051
if (!response.ok) {
21-
return NextResponse.json({ error: "Recording not found" }, { status: 404 });
52+
return NextResponse.json({ error: "Recording not available" }, { status: 404 });
2253
}
2354

2455
const buffer = Buffer.from(await response.arrayBuffer());

src/app/elderly/[id]/assessment/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ export default function AssessmentPage() {
607607
{a.recordingUrl && (
608608
<div className="ml-5 mt-1">
609609
<audio controls preload="none" className="h-7 w-full max-w-xs">
610-
<source src={a.recordingUrl} type="audio/mpeg" />
610+
<source src={`/api/recording?url=${encodeURIComponent(a.recordingUrl)}`} type="audio/mpeg" />
611611
</audio>
612612
</div>
613613
)}

src/lib/assessment-call.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export async function executeAssessmentCall(sessionId: string) {
6161
const q1Url = questionUrls[0];
6262

6363
const baseUrl = process.env.NEXT_PUBLIC_APP_URL;
64-
const lang = profile.language === "ar" ? "ar-SA" : "en-US";
6564

6665
const twiml = `<Response>
6766
<Play>${greetingUrl}</Play>

0 commit comments

Comments
 (0)