1 rows = same person in several * tenants/workspaces (the callback shows a chooser). */ function sassly_find_or_link_users(array $identity): array { $pdo = sassly_app_pdo(); $sub = (string)$identity['sub']; $email = is_string($identity['email'] ?? null) ? strtolower(trim($identity['email'])) : ''; if ($email !== '' && ($identity['email_verified'] ?? false) === true) { $link = $pdo->prepare('UPDATE users SET sassly_sub = ? WHERE LOWER(email) = ? AND sassly_sub IS NULL'); $link->execute([$sub, $email]); } $st = $pdo->prepare('SELECT * FROM users WHERE sassly_sub = ? AND is_active = 1 ORDER BY id'); $st->execute([$sub]); return $st->fetchAll(PDO::FETCH_ASSOC); } /** * The logged-in user on each request. Must return null when the user was disabled in the app or is no * longer linked to this sub — that is how an employee deactivated in Haris loses access here. */ function sassly_load_active_user(int|string $userId, string $sub): ?array { $st = sassly_app_pdo()->prepare('SELECT * FROM users WHERE id = ? AND sassly_sub = ? AND is_active = 1'); $st->execute([$userId, $sub]); $row = $st->fetch(PDO::FETCH_ASSOC); return $row === false ? null : $row; } /** ADAPT: label shown in the workspace chooser, e.g. tenant name + role. Plain text (escaped later). */ function sassly_user_label(array $user): string { return (string)($user['company_name'] ?? $user['email'] ?? ('User #' . $user['id'])); } /** ADAPT: set the session keys the existing app code reads; update last login if the app tracks it. */ function sassly_on_login(array $user, array $identity): void { $_SESSION['user_id'] = $user['id']; } /** ADAPT: every app session key that sassly_on_login() sets (cleared when the Sassly login ends). */ function sassly_app_session_keys(): array { return ['user_id']; }