Update 3 files
This commit is contained in:
1 parent
2db87a1227
commit
63b81b4764
3 files changed
+55
-3
No files matched your search
@@ -207,3 +207,13 @@ Status: implemented
|
|||||||
vice principals cannot remove conversation records.
|
vice principals cannot remove conversation records.
|
||||||
- Administrative room closure verifies the administrator belongs to the room's
|
- Administrative room closure verifies the administrator belongs to the room's
|
||||||
school.
|
school.
|
||||||
|
|
||||||
|
## Phase 8: Leave Record Integrity
|
||||||
|
|
||||||
|
Status: implemented
|
||||||
|
|
||||||
|
- Teacher absence detail endpoints now require authentication, school scope,
|
||||||
|
and either the absence owner or an administrator.
|
||||||
|
- Teachers cannot alter status, or edit/delete a leave once it is approved.
|
||||||
|
- Vice principals cannot delete student leave records; reporters may only
|
||||||
|
withdraw requests before either approval stage is processed.
|
||||||
@@ -189,11 +189,18 @@ export async function DELETE(
|
|||||||
const role = session.user?.role;
|
const role = session.user?.role;
|
||||||
const userId = session.userId;
|
const userId = session.userId;
|
||||||
|
|
||||||
// Only the reporter or admin can delete
|
// Only the reporter can withdraw a still-pending request. Final approval
|
||||||
if (role !== 'SUPER_ADMIN' && role !== 'SCHOOL_ADMIN' && role !== 'VICE_PRINCIPAL') {
|
// records cannot be removed by vice principals.
|
||||||
|
if (role !== 'SUPER_ADMIN' && role !== 'SCHOOL_ADMIN') {
|
||||||
if (report.reportedBy !== userId) {
|
if (report.reportedBy !== userId) {
|
||||||
return NextResponse.json({ error: 'Only the reporter or admin can delete' }, { status: 403 });
|
return NextResponse.json({ error: 'Only the reporter or admin can delete' }, { status: 403 });
|
||||||
}
|
}
|
||||||
|
if (report.parentApprovalStatus !== 'pending' || report.adminApprovalStatus !== 'pending') {
|
||||||
|
return NextResponse.json({ error: 'Approved or reviewed reports cannot be deleted by the reporter' }, { status: 400 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (role !== 'SUPER_ADMIN' && role !== 'STUDENT' && role !== 'PARENT' && report.schoolId !== session.user?.schoolId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.illnessReport.delete({ where: { id } });
|
await db.illnessReport.delete({ where: { id } });
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import { db } from '@/lib/db';
|
import { db } from '@/lib/db';
|
||||||
|
import { getSession } from '@/lib/auth';
|
||||||
|
|
||||||
|
function canManageAbsence(role: string | undefined, teacherId: string, userId: string): boolean {
|
||||||
|
return role === 'SUPER_ADMIN' || role === 'SCHOOL_ADMIN' || (role === 'TEACHER' && teacherId === userId);
|
||||||
|
}
|
||||||
|
|
||||||
// GET /api/substitutes/absences/[id] - Get a single absence
|
// GET /api/substitutes/absences/[id] - Get a single absence
|
||||||
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
try {
|
try {
|
||||||
|
const session = await getSession();
|
||||||
|
if (!session) return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const absence = await db.teacherAbsence.findUnique({
|
const absence = await db.teacherAbsence.findUnique({
|
||||||
where: { id },
|
where: { id },
|
||||||
@@ -22,6 +29,12 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
if (!absence) {
|
if (!absence) {
|
||||||
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
if (!canManageAbsence(session.user?.role, absence.teacherId, session.userId)) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
if (session.user?.role !== 'SUPER_ADMIN' && absence.schoolId !== session.user?.schoolId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json(absence);
|
return NextResponse.json(absence);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -33,6 +46,8 @@ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
// PUT /api/substitutes/absences/[id] - Update an absence
|
// PUT /api/substitutes/absences/[id] - Update an absence
|
||||||
export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
try {
|
try {
|
||||||
|
const session = await getSession();
|
||||||
|
if (!session) return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const body = await req.json();
|
const body = await req.json();
|
||||||
|
|
||||||
@@ -40,9 +55,18 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
if (!existing) {
|
if (!existing) {
|
||||||
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
if (!canManageAbsence(session.user?.role, existing.teacherId, session.userId)) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
if (session.user?.role !== 'SUPER_ADMIN' && existing.schoolId !== session.user?.schoolId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
if (existing.approvalStatus !== 'pending' && session.user?.role === 'TEACHER') {
|
||||||
|
return NextResponse.json({ error: 'Approved leave cannot be edited by the teacher' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
const data: Record<string, unknown> = {};
|
const data: Record<string, unknown> = {};
|
||||||
const simpleFields = ['type', 'reason', 'status', 'notes'];
|
const simpleFields = session.user?.role === 'TEACHER' ? ['type', 'reason', 'notes'] : ['type', 'reason', 'status', 'notes'];
|
||||||
|
|
||||||
for (const field of simpleFields) {
|
for (const field of simpleFields) {
|
||||||
if (body[field] !== undefined) data[field] = body[field];
|
if (body[field] !== undefined) data[field] = body[field];
|
||||||
@@ -70,12 +94,23 @@ export async function PUT(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
// DELETE /api/substitutes/absences/[id] - Delete an absence
|
// DELETE /api/substitutes/absences/[id] - Delete an absence
|
||||||
export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
try {
|
try {
|
||||||
|
const session = await getSession();
|
||||||
|
if (!session) return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
|
|
||||||
const existing = await db.teacherAbsence.findUnique({ where: { id } });
|
const existing = await db.teacherAbsence.findUnique({ where: { id } });
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
return NextResponse.json({ error: 'Absence not found' }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
if (!canManageAbsence(session.user?.role, existing.teacherId, session.userId)) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
if (session.user?.role !== 'SUPER_ADMIN' && existing.schoolId !== session.user?.schoolId) {
|
||||||
|
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
|
||||||
|
}
|
||||||
|
if (existing.approvalStatus === 'approved' && session.user?.role === 'TEACHER') {
|
||||||
|
return NextResponse.json({ error: 'Approved leave cannot be deleted by the teacher' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
// Delete associated assignments first
|
// Delete associated assignments first
|
||||||
await db.substitutionAssignment.deleteMany({ where: { absenceId: id } });
|
await db.substitutionAssignment.deleteMany({ where: { absenceId: id } });
|
||||||
|
|||||||
Reference in new issue
Block a user