Newer
Older
smart-home-server / server / SHServ / Integrations / GAuth / UserResolver.php
@Eugene Sukhodolskiy Eugene Sukhodolskiy 21 hours ago 3 KB Phase 0: gnexus-auth integration infrastructure
<?php

declare(strict_types=1);

namespace SHServ\Integrations\GAuth;

use GNexus\GAuth\DTO\AuthenticatedUser;
use GNexus\GAuth\DTO\ClientAccess;

final class UserResolver
{
    /**
     * Upsert user from AuthenticatedUser DTO into shserv_users.
     * Returns local user ID.
     */
    public function resolve(AuthenticatedUser $user): int
    {
        $tb = app()->thin_builder;

        // Find existing by gauth_user_id
        $existing = $tb->select('shserv_users', ['id'], [['gauth_user_id', '=', $user->userId]]);

        // Extract client access for this Client
        $clientAccess = $this->findClientAccess($user);
        $systemRole = $user->systemRole ?? 'user';
        $status = $user->status ?? 'active';
        $displayName = $user->profile['display_name'] ?? ($user->profile['username'] ?? $user->email);
        $avatarUrl = $user->avatarUrl();

        $data = [
            'email' => $user->email,
            'display_name' => $displayName,
            'avatar_url' => $avatarUrl,
            'system_role' => $systemRole,
            'status' => $status,
        ];

        if ($existing) {
            $userId = (int) $existing[0]['id'];
            $tb->update('shserv_users', $data, [['id', '=', $userId]]);

            // Sync permissions from client access
            $this->syncPermissions($userId, $clientAccess);

            return $userId;
        }

        $data['gauth_user_id'] = $user->userId;
        $data['created_at'] = date('Y-m-d H:i:s');

        $tb->insert('shserv_users', $data);
        $userId = (int) $tb->getLastInsertedId();

        $this->syncPermissions($userId, $clientAccess);

        return $userId;
    }

    private function findClientAccess(AuthenticatedUser $user): ?ClientAccess
    {
        $clientId = FCONF['gauth']['client_id'] ?? '';
        foreach ($user->clientAccessList as $access) {
            if ($access->clientId === $clientId) {
                return $access;
            }
        }
        return null;
    }

    private function syncPermissions(int $userId, ?ClientAccess $access): void
    {
        if (!$access) {
            return;
        }

        $tb = app()->thin_builder;

        // Remove old auto-synced permissions (those without set_by_user_id = manual override)
        $tb->query("
            DELETE FROM shserv_user_permissions
            WHERE user_id = {$userId} AND set_by_user_id IS NULL
        ");

        // Insert current permissions from gnexus-auth
        foreach ($access->permissionIds as $permId) {
            $permSlug = $this->mapPermissionIdToSlug($permId);
            if (!$permSlug) {
                continue;
            }
            $tb->insert('shserv_user_permissions', [
                'user_id' => $userId,
                'permission_slug' => $permSlug,
                'granted' => 1,
                'set_by_user_id' => null,
            ]);
        }
    }

    private function mapPermissionIdToSlug(string $permId): ?string
    {
        // In first version, gnexus-auth permissionIds might be slugs already.
        // If they are numeric IDs, we would need a mapping table.
        // For now, assume they are strings like "devices.view".
        $tb = app()->thin_builder;
        $exists = $tb->select('shserv_permissions', ['slug'], [['slug', '=', $permId]], [], '', [0, 1]);
        return $exists ? $exists[0]['slug'] : null;
    }
}