see comments from commit #88

This commit is contained in:
Rajpreet0 2026-05-05 10:56:10 +02:00
parent 87dd836ddc
commit a17047895b
4 changed files with 98 additions and 22 deletions

View file

@ -145,7 +145,12 @@ export const getUserData = cache(async (): Promise<AuthUserData | null> => {
let permissions: EmployeeData["permissions"];
if (raw && ("canCreateCourses" in raw || "canCreateEmployees" in raw)) {
if (
raw &&
typeof raw === "object" &&
!Array.isArray(raw) &&
("canCreateCourses" in raw || "canCreateEmployees" in raw)
) {
// Backward-Kompatibilität: altes Format migrieren
const old = raw as { canCreateCourses?: boolean; canCreateEmployees?: boolean };
permissions = {
@ -210,6 +215,14 @@ export const getUserData = cache(async (): Promise<AuthUserData | null> => {
)(user.email, user.id);
});
// Returns the effective manager ID for any user type.
// For Employees, this is createdBy (the manager who created them).
// Returns null if the employee is orphaned (no manager mapping) — callers must handle this.
export function getEffectiveManagerId(userData: AuthUserData): string | null {
if (isEmployee(userData)) return userData.createdBy;
return userData.id;
}
export async function requireAuth() {
const user = await getUser();
return user!;

View file

@ -9,7 +9,7 @@
"use server";
import { prisma } from "@/src/lib/prisma";
import { getUserData, isManager, isEmployee } from "@/src/lib/auth/getUser";
import { getUserData, isManager, isEmployee, getEffectiveManagerId } from "@/src/lib/auth/getUser";
import { courseSchema, publishedCourseSchema, type CourseFormData } from "../schemas/course-schema";
import { revalidatePath } from "next/cache";
import { Prisma } from "@prisma/client";
@ -63,7 +63,9 @@ export async function createCourse(data: CourseFormData, status: "draft" | "publ
const validatedData = validation.data;
// Schritt 5: Manager-ID ermitteln (Employee erbt createdBy vom eigenen Datensatz)
const creatorId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const creatorId = getEffectiveManagerId(userData);
if (!creatorId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 6: Kurs in der Datenbank erstellen
const course = await prisma.course.create({
@ -173,7 +175,13 @@ export async function getMyCourses(options?: { dateFrom?: Date; dateTo?: Date })
}
// Step 3: Manager-ID ermitteln (Employee erbt createdBy vom eigenen Datensatz)
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
courses: [],
};
// Step 4: Build the where clause with optional date filtering
const whereClause: Prisma.CourseWhereInput = {
@ -248,7 +256,9 @@ export async function getCourseById(courseId: string) {
}
// Schritt 3: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 4: Kurs aus der Datenbank abrufen
const course = await prisma.course.findUnique({
@ -324,7 +334,9 @@ export async function updateCourse(
}
// Schritt 4: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 5: Kurs aus der Datenbank abrufen
const existingCourse = await prisma.course.findUnique({
@ -434,7 +446,9 @@ export async function deleteCourse(courseId: string) {
}
// Schritt 3: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 4: Kurs aus der Datenbank abrufen
const course = await prisma.course.findUnique({
@ -492,7 +506,13 @@ export async function getMySportTypes() {
return { success: false, error: "Unauthorized", sports: [] };
}
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
sports: [],
};
const courses = await prisma.course.findMany({
where: { createdBy: managerId },
@ -522,7 +542,13 @@ export async function getMyBusinesses() {
return { success: false, error: "Unauthorized", businesses: [] };
}
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
businesses: [],
};
const businesses = await prisma.business.findMany({
where: { managerId },

View file

@ -9,7 +9,7 @@
"use server";
import { prisma } from "@/src/lib/prisma";
import { getUserData, isManager, isEmployee } from "@/src/lib/auth/getUser";
import { getUserData, isManager, isEmployee, getEffectiveManagerId } from "@/src/lib/auth/getUser";
import { createAdminClient } from "@/src/lib/supabase/admin";
import { employeeSchema, type EmployeeFormData } from "../schemas/employee-schema";
import { revalidatePath, revalidateTag } from "next/cache";
@ -129,7 +129,9 @@ export async function createEmployee(data: EmployeeFormData, status: "draft" | "
}
// Schritt 7: Manager-ID ermitteln (Employee erbt createdBy vom eigenen Datensatz)
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 8: Berechtigungen auf Caller-Ceiling begrenzen (Privilege-Escalation verhindern)
const finalPermissions = isEmployee(userData)
@ -216,7 +218,14 @@ export async function getMyTrainers() {
};
}
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
employees: [],
trainers: [],
};
const employees = await prisma.employee.findMany({
where: {
@ -282,8 +291,12 @@ export async function getMyEmployees() {
// Manager sieht alle Mitarbeiter unter seiner ID
whereClause = { createdBy: userData.id };
} else {
// Employee: eigene Manager-ID ermitteln, dann alle unter diesem Manager anzeigen (außer sich selbst)
// Employee: alle unter demselben Manager anzeigen (außer sich selbst)
// createdBy kann null sein (verwaister Account) — in dem Fall nichts zurückgeben
const managerId = userData.createdBy;
if (!managerId) {
return { success: true, employees: [] };
}
whereClause = { createdBy: managerId, NOT: { email: userData.email } };
}
const employees = await prisma.employee.findMany({
@ -435,7 +448,9 @@ export async function updateEmployee(
}
// Schritt 6: Überprüfen, ob der Benutzer der Besitzer des Mitarbeiters ist
const ownerManagerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const ownerManagerId = getEffectiveManagerId(userData);
if (!ownerManagerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
if (existingEmployee.createdBy !== ownerManagerId) {
return {
success: false,
@ -568,7 +583,13 @@ export async function getMyEmployeeRoles() {
}
// Schritt 3: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
roles: [],
};
// Schritt 4: Alle Mitarbeiter des Managers abrufen (nur roles Feld)
const employees = await prisma.employee.findMany({
@ -653,7 +674,9 @@ export async function deleteEmployee(employeeId: string) {
}
// Schritt 5: Überprüfen, ob der Benutzer der Besitzer des Mitarbeiters ist
const ownerManagerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const ownerManagerId = getEffectiveManagerId(userData);
if (!ownerManagerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
if (employee.createdBy !== ownerManagerId) {
return {
success: false,

View file

@ -9,7 +9,7 @@
"use server";
import { prisma } from "@/src/lib/prisma";
import { getUserData, isManager, isEmployee } from "@/src/lib/auth/getUser";
import { getUserData, isManager, isEmployee, getEffectiveManagerId } from "@/src/lib/auth/getUser";
import { roomSchema, type RoomFormData } from "../schemas/room-schema";
import { revalidatePath } from "next/cache";
@ -59,7 +59,9 @@ export async function createRoom(data: RoomFormData) {
const validatedData = validation.data;
// Schritt 5: Manager-ID ermitteln (Employee erbt createdBy vom eigenen Datensatz)
const creatorId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const creatorId = getEffectiveManagerId(userData);
if (!creatorId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 6: Raum in der Datenbank erstellen
const room = await prisma.room.create({
@ -143,7 +145,13 @@ export async function getMyRooms() {
}
// Schritt 3: Manager-ID ermitteln (Employee erbt createdBy vom eigenen Datensatz)
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return {
success: false,
error: "Mitarbeiter-Account ist keinem Manager zugeordnet",
rooms: [],
};
// Schritt 4: Räume abrufen, die von diesem Manager erstellt wurden
const rooms = await prisma.room.findMany({
@ -195,7 +203,9 @@ export async function getRoomById(roomId: string) {
}
// Schritt 3: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 4: Raum aus der Datenbank abrufen
const room = await prisma.room.findUnique({
@ -267,7 +277,9 @@ export async function updateRoom(roomId: string, data: RoomFormData) {
}
// Schritt 4: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 5: Raum aus der Datenbank abrufen
const existingRoom = await prisma.room.findUnique({
@ -356,7 +368,9 @@ export async function deleteRoom(roomId: string) {
}
// Schritt 3: Effektive Manager-ID ermitteln
const managerId = isEmployee(userData) ? (userData.createdBy ?? userData.id) : userData.id;
const managerId = getEffectiveManagerId(userData);
if (!managerId)
return { success: false, error: "Mitarbeiter-Account ist keinem Manager zugeordnet" };
// Schritt 4: Raum aus der Datenbank abrufen
const room = await prisma.room.findUnique({