Initial commit: ExaMetra v1.0.0 — Free & open-source competence & grading platform

Features:
- 15+ views: Dashboard, Classes, Progress, Flower, Matrix, Assessments, Grading, Reports, Attendance, Calendar, Lesson Plans, Analytics, Parent Communication, Behavior Tracking, Settings
- 34+ API endpoints
- 30+ Prisma models
- 700+ i18n keys (German + English)
- Keyboard shortcuts (Cmd+K, Cmd+1-9, Cmd+/)
- Batch deletion, drag-and-drop seating, custom color palette
- Demo accounts (admin, teacher, student, parent)
- Dark mode, responsive design, print styles
- CSV/PDF export, notification system, onboarding tour
- Zero emojis — all replaced with Lucide icons
- MIT License
This commit is contained in:
Mustafa Cetin committed 2026-07-29 05:46:10 +00:00
commit 0c1f739989
156 files changed
+51090

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
import bcrypt from 'bcryptjs';
import { cookies } from 'next/headers';
import { Prisma } from '@prisma/client';
import { db } from '@/lib/db';
const SESSION_COOKIE_NAME = 'ct_session';
const SESSION_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
export async function hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
}
export async function verifyPassword(
password: string,
hash: string
): Promise<boolean> {
return bcrypt.compare(password, hash);
}
export async function createSession(userId: string): Promise<void> {
const cookieStore = await cookies();
cookieStore.set(SESSION_COOKIE_NAME, userId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: SESSION_COOKIE_MAX_AGE,
path: '/',
});
}
const sessionUserSelect = Prisma.validator<Prisma.UserSelect>()({
id: true,
email: true,
firstName: true,
lastName: true,
role: true,
schoolId: true,
locale: true,
isDemo: true,
createdAt: true,
updatedAt: true,
});
export type SessionUser = Prisma.UserGetPayload<{ select: typeof sessionUserSelect }>;
export async function getSession(): Promise<{
userId: string;
user: SessionUser | null;
} | null> {
const cookieStore = await cookies();
const userId = cookieStore.get(SESSION_COOKIE_NAME)?.value;
if (!userId) return null;
const user = await db.user.findUnique({
where: { id: userId, deletedAt: null },
select: sessionUserSelect,
});
if (!user) return null;
return { userId, user };
}
export async function clearSession(): Promise<void> {
const cookieStore = await cookies();
cookieStore.delete(SESSION_COOKIE_NAME);
}