[dyad] Kalan branding alt başlığını kaldır

This commit is contained in:
[dyad] committed 2026-08-02 16:07:54 +02:00
1 parent 71b9ca0eb4
commit b9e4ed4dfc
42 files changed
+168 -37

No files matched your search

@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { logAudit, extractClientInfo } from '@/lib/audit';
import { canAccessStudent } from '@/lib/access-policy';
export async function GET(request: Request) {
try {
@@ -31,6 +32,9 @@ export async function GET(request: Request) {
deletedAt: null,
};
if (studentId && (!session.user || !(await canAccessStudent(session.user, studentId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (studentId) where.studentId = studentId;
if (incidentId) where.incidentId = incidentId;
if (type) where.type = type;
@@ -87,6 +91,15 @@ export async function POST(request: Request) {
{ status: 400 }
);
}
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (session.user?.role !== 'TEACHER' && session.user?.role !== 'SCHOOL_ADMIN' && session.user?.role !== 'SUPER_ADMIN') {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const intervention = await db.behaviorIntervention.create({
data: {
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
export async function GET(
_request: Request,
@@ -36,6 +37,12 @@ export async function GET(
if (!disciplinaryCase) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
if (session.user?.role !== 'SUPER_ADMIN' && disciplinaryCase.schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, disciplinaryCase.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(disciplinaryCase);
} catch (error) {
@@ -62,6 +69,12 @@ export async function PUT(
if (!existing) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
if (session.user?.role !== 'SUPER_ADMIN' && existing.schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const role = session.user?.role;
const userId = session.userId;
+11 -1
View File
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
export async function GET(request: Request) {
try {
@@ -13,12 +14,15 @@ export async function GET(request: Request) {
const schoolId = searchParams.get('schoolId') ?? session.user?.schoolId;
const status = searchParams.get('status');
const committeeId = searchParams.get('committeeId');
const role = session.user?.role;
if (!schoolId) {
return NextResponse.json([]);
}
if (role !== 'SUPER_ADMIN' && schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const role = session.user?.role;
const userId = session.userId;
const where: Record<string, unknown> = { schoolId };
@@ -80,6 +84,12 @@ export async function POST(request: Request) {
if (!schoolId || !committeeId || !studentId || !caseType || !description) {
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}
if (role !== 'SUPER_ADMIN' && schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const newCase = await db.disciplinaryCase.create({
data: {
@@ -1,6 +1,8 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
import { isAdministrator } from '@/lib/role-access';
export async function GET(
_request: Request,
@@ -29,6 +31,9 @@ export async function GET(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== contact.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!isAdministrator(session.user?.role) || !session.user || !(await canAccessStudent(session.user, contact.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(contact);
} catch (error) {
@@ -59,6 +64,9 @@ export async function PUT(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!isAdministrator(session.user?.role) || !session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const body = await request.json();
const {
@@ -122,6 +130,9 @@ export async function DELETE(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!isAdministrator(session.user?.role) || !session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Soft delete
await db.emergencyContact.update({
+10
View File
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
export async function GET(
_request: Request,
@@ -38,6 +39,9 @@ export async function GET(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== goal.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, goal.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(goal);
} catch (error) {
@@ -68,6 +72,9 @@ export async function PUT(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const body = await request.json();
const {
@@ -132,6 +139,9 @@ export async function DELETE(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Soft delete
await db.learningGoal.update({
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
// ── PUT: Return a book (or renew) ──────────────────────────────────
export async function PUT(
@@ -35,6 +36,12 @@ export async function PUT(
if (!checkout) {
return NextResponse.json({ error: 'Checkout not found' }, { status: 404 });
}
if (session.user?.role !== 'SUPER_ADMIN' && checkout.schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, checkout.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (action === 'return') {
// Return the book
@@ -153,6 +160,14 @@ export async function DELETE(
}
const { id } = await params;
const checkout = await db.bookCheckout.findUnique({ where: { id } });
if (!checkout) return NextResponse.json({ error: 'Checkout not found' }, { status: 404 });
if (session.user?.role !== 'SUPER_ADMIN' && checkout.schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, checkout.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
await db.bookCheckout.delete({ where: { id } });
return NextResponse.json({ success: true });
+16 -1
View File
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server';
import { z } from 'zod';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessClass, canAccessStudent } from '@/lib/access-policy';
export async function GET(
_request: Request,
@@ -19,7 +20,7 @@ export async function GET(
include: {
student: { select: { id: true, firstName: true, lastName: true, avatarUrl: true, dateOfBirth: true } },
classGroup: {
select: { id: true, name: true, gradeLevel: true, schoolType: true, responsibleTeacher: { select: { id: true, firstName: true, lastName: true } } },
select: { id: true, schoolId: true, name: true, gradeLevel: true, schoolType: true, responsibleTeacher: { select: { id: true, firstName: true, lastName: true } } },
},
schoolYear: { select: { id: true, label: true, startDate: true, endDate: true } },
generatedByUser: { select: { id: true, firstName: true, lastName: true } },
@@ -36,6 +37,12 @@ export async function GET(
if (!report) {
return NextResponse.json({ error: 'Report not found' }, { status: 404 });
}
if (session.user?.role !== 'SUPER_ADMIN' && report.classGroup.schoolId !== session.user?.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, report.studentId)) || !(await canAccessClass(session.user, report.classGroupId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Role-based access check
if (session.user?.role === 'STUDENT') {
@@ -123,6 +130,10 @@ export async function PUT(
}
const { sections, ...updateData } = parsed.data;
const existingReport = await db.report.findUnique({ where: { id }, select: { studentId: true, classGroupId: true, classGroup: { select: { schoolId: true } } } });
if (!existingReport || !session.user || (session.user.role !== 'SUPER_ADMIN' && existingReport.classGroup.schoolId !== session.user.schoolId) || !(await canAccessStudent(session.user, existingReport.studentId)) || !(await canAccessClass(session.user, existingReport.classGroupId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Check if teacher owns this report
if (session.user?.role === 'TEACHER') {
@@ -207,6 +218,10 @@ export async function DELETE(
}
const { id } = await params;
const existing = await db.report.findUnique({ where: { id }, select: { studentId: true, classGroupId: true, classGroup: { select: { schoolId: true } } } });
if (!existing || !session.user || (session.user.role !== 'SUPER_ADMIN' && existing.classGroup.schoolId !== session.user.schoolId) || !(await canAccessStudent(session.user, existing.studentId)) || !(await canAccessClass(session.user, existing.classGroupId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
await db.reportSection.deleteMany({ where: { reportId: id } });
await db.report.delete({ where: { id } });
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessClass, canAccessStudent } from '@/lib/access-policy';
export async function GET(
_request: Request,
@@ -38,6 +39,9 @@ export async function GET(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== assessment.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, assessment.studentId)) || (assessment.classGroupId && !(await canAccessClass(session.user, assessment.classGroupId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
return NextResponse.json(assessment);
} catch (error) {
@@ -68,6 +72,9 @@ export async function PUT(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId)) || (existing.classGroupId && !(await canAccessClass(session.user, existing.classGroupId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const body = await request.json();
const {
@@ -134,6 +141,9 @@ export async function DELETE(
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId)) || (existing.classGroupId && !(await canAccessClass(session.user, existing.classGroupId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
// Soft delete
await db.selfAssessment.update({
+13
View File
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessClass, canAccessStudent } from '@/lib/access-policy';
export async function GET(request: Request) {
try {
@@ -28,6 +29,12 @@ export async function GET(request: Request) {
deletedAt: null,
};
if (studentId && (!session.user || !(await canAccessStudent(session.user, studentId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (classGroupId && (!session.user || !(await canAccessClass(session.user, classGroupId)))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (studentId) where.studentId = studentId;
if (competencyId) where.competencyId = competencyId;
if (classGroupId) where.classGroupId = classGroupId;
@@ -96,6 +103,12 @@ export async function POST(request: Request) {
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (classGroupId && !(await canAccessClass(session.user, classGroupId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const assessment = await db.selfAssessment.create({
data: {
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
try {
@@ -13,6 +14,12 @@ export async function PUT(request: Request, { params }: { params: Promise<{ id:
// Verify the plan belongs to the student
const existing = await db.studyPlan.findUnique({ where: { id } });
if (!existing) return NextResponse.json({ error: 'Plan not found' }, { status: 404 });
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (session.user?.role === 'STUDENT') {
const student = await db.student.findFirst({
@@ -62,6 +69,12 @@ export async function DELETE(request: Request, { params }: { params: Promise<{ i
const existing = await db.studyPlan.findUnique({ where: { id } });
if (!existing) return NextResponse.json({ error: 'Plan not found' }, { status: 404 });
if (session.user?.role !== 'SUPER_ADMIN' && session.user?.schoolId !== existing.schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (!session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (session.user?.role === 'STUDENT') {
const student = await db.student.findFirst({
+5 -19
View File
@@ -1,6 +1,7 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSession } from '@/lib/auth';
import { canAccessStudent } from '@/lib/access-policy';
export async function POST(request: Request) {
try {
@@ -26,15 +27,8 @@ export async function POST(request: Request) {
return NextResponse.json({ error: 'Missing required fields' }, { status: 400 });
}
// Verify access
if (session.user?.role === 'STUDENT') {
const student = await db.student.findUnique({
where: { id: studentId },
select: { userId: true, schoolId: true },
});
if (!student || student.userId !== session.userId || student.schoolId !== schoolId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (session.user?.role !== 'STUDENT' || schoolId !== session.user?.schoolId || !session.user || !(await canAccessStudent(session.user, studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const studySession = await db.studySession.create({
@@ -99,16 +93,8 @@ export async function PUT(request: Request) {
const existing = await db.studySession.findUnique({ where: { id: sessionId } });
if (!existing) return NextResponse.json({ error: 'Session not found' }, { status: 404 });
// Verify access
if (session.user?.role === 'STUDENT') {
const student = await db.student.findFirst({
where: { userId: session.userId, schoolId: existing.schoolId, deletedAt: null },
select: { id: true },
});
if (!student || student.id !== existing.studentId) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
if (session.user?.role !== 'STUDENT' || existing.schoolId !== session.user?.schoolId || !session.user || !(await canAccessStudent(session.user, existing.studentId))) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
}
const updated = await db.studySession.update({
+1 -1
View File
@@ -4,7 +4,7 @@ import { ThemeProvider } from "next-themes";
import { Toaster } from "@/components/ui/sonner";
export const metadata: Metadata = {
title: "SchulOS — Free Competency & Grading Platform",
title: "SchulOS",
description: "Open-Source School Software for Competency-Based Assessment and Grading. Built with Next.js, TypeScript, and shadcn/ui.",
keywords: ["SchulOS", "competency", "grading", "school", "education", "Next.js", "TypeScript", "shadcn/ui"],
authors: [{ name: "SchulOS Team" }],
+2 -3
View File
@@ -986,8 +986,7 @@ export default function AppLayout() {
</div>
)}
<div className="group-data-[collapsible=icon]:hidden">
<h2 className="text-lg font-bold text-gray-900 dark:text-gray-100 leading-tight">{schoolBranding?.name || 'SchulOS'}</h2>
<p className="text-[10px] text-emerald-600/70 dark:text-emerald-400/50 leading-tight">{t('app.subtitle')}</p>
<h2 className="text-lg font-bold text-gray-900 dark:text-gray-100 leading-tight">SchulOS</h2>
</div>
</motion.div>
</SidebarHeader>
@@ -1420,7 +1419,7 @@ export default function AppLayout() {
<div className="flex items-center justify-between text-xs text-emerald-600/60 dark:text-emerald-400/40">
<span className="flex items-center gap-1">
<Leaf className="h-3 w-3 text-emerald-500" />
SchulOS — {t('footer.copyright')}
SchulOS
</span>
<span className="flex items-center gap-2">
<span className="hidden sm:inline">{t('footer.version')} · {t('footer.oss')}</span>