<?php
declare(strict_types=1);
require_once __DIR__.'/auth.php';require_once __DIR__.'/permissoes_ti.php';tiPermExigir($mysqli,'usuarios_permissoes','administrar');$mysqli->set_charset('utf8mb4');
function upCsrf():string{if(empty($_SESSION['csrf_usuarios_perm']))$_SESSION['csrf_usuarios_perm']=bin2hex(random_bytes(24));return (string)$_SESSION['csrf_usuarios_perm'];}
function upValidar():void{$r=(string)($_POST['csrf_token']??'');$e=(string)($_SESSION['csrf_usuarios_perm']??'');if($r===''||$e===''||!hash_equals($e,$r))throw new RuntimeException('Sessão expirada. Atualize a página.');}
function upNivelFlags(string $n):array{return match($n){'consulta'=>[1,0,0,0,0,0,1,0],'operador'=>[1,1,1,0,1,1,1,0],'total'=>[1,1,1,1,1,1,1,1],default=>[0,0,0,0,0,0,0,0]};}
function upNivelAtual(array $p):string{$v=[(int)$p['pode_visualizar'],(int)$p['pode_cadastrar'],(int)$p['pode_editar'],(int)$p['pode_excluir'],(int)$p['pode_transferir'],(int)$p['pode_finalizar'],(int)$p['pode_exportar'],(int)$p['pode_administrar']];if($v===[1,1,1,1,1,1,1,1])return'total';if($v===[1,1,1,0,1,1,1,0])return'operador';if($v[0]===1&&array_sum(array_slice($v,1))<=1)return'consulta';return array_sum($v)>0?'personalizado':'sem';}
function upFlash(string $t,string $m):void{$_SESSION['up_flash']=['tipo'=>$t,'mensagem'=>$m];}function upGetFlash():?array{$f=$_SESSION['up_flash']??null;unset($_SESSION['up_flash']);return is_array($f)?$f:null;}
$csrf=upCsrf();$erro='';
if($_SERVER['REQUEST_METHOD']==='POST'){
 try{upValidar();$acao=(string)($_POST['acao']??'');$admin=tiPermUsuario();
  if($acao==='criar_usuario'){$usuario=trim((string)($_POST['usuario']??''));$senha=(string)($_POST['senha']??'');$nome=trim((string)($_POST['nome_exibicao']??''));$email=trim((string)($_POST['email']??''));$ativo=!empty($_POST['ativo'])?1:0;$home=trim((string)($_POST['pagina_inicial']??''));if(!preg_match('/^[A-Za-zÀ-ÿ0-9._-]{3,50}$/u',$usuario))throw new RuntimeException('O usuário deve possuir de 3 a 50 caracteres válidos.');if(strlen($senha)<8)throw new RuntimeException('A senha inicial deve possuir pelo menos 8 caracteres.');$stmt=$mysqli->prepare('SELECT id FROM usuarios WHERE LOWER(usuario)=LOWER(?) LIMIT 1');$stmt->bind_param('s',$usuario);$stmt->execute();if($stmt->get_result()->fetch_assoc()){throw new RuntimeException('Já existe um usuário com esse login.');}$stmt->close();$hash=password_hash($senha,PASSWORD_DEFAULT);$mysqli->begin_transaction();$stmt=$mysqli->prepare('INSERT INTO usuarios(usuario,senha) VALUES(?,?)');$stmt->bind_param('ss',$usuario,$hash);$stmt->execute();$uid=(int)$stmt->insert_id;$stmt->close();$stmt=$mysqli->prepare('INSERT INTO ti_usuarios_config(user_id,nome_exibicao,email,ativo,admin_global,pagina_inicial,forcar_troca_senha,atualizado_por) VALUES(?,?,?,?,0,?,1,?)');$stmt->bind_param('ississ',$uid,$nome,$email,$ativo,$home,$admin);$stmt->execute();$stmt->close();foreach($_POST['nivel']??[] as $mod=>$nivel){$f=upNivelFlags((string)$nivel);$stmt=$mysqli->prepare('INSERT INTO ti_usuario_permissoes(user_id,modulo_slug,pode_visualizar,pode_cadastrar,pode_editar,pode_excluir,pode_transferir,pode_finalizar,pode_exportar,pode_administrar,atualizado_por) VALUES(?,?,?,?,?,?,?,?,?,?,?)');$stmt->bind_param('isiiiiiiiis',$uid,$mod,$f[0],$f[1],$f[2],$f[3],$f[4],$f[5],$f[6],$f[7],$admin);$stmt->execute();$stmt->close();}$mysqli->commit();tiPermRegistrarAuditoria($mysqli,'USUARIO_CRIADO','usuarios_permissoes',$uid,'Login: '.$usuario);upFlash('sucesso','Usuário criado. A troca da senha inicial ficou marcada como obrigatória.');header('Location: usuarios_permissoes.php?editar='.$uid);exit;}
  if($acao==='atualizar_usuario'){$uid=(int)($_POST['user_id']??0);$stmt=$mysqli->prepare('SELECT usuario FROM usuarios WHERE id=?');$stmt->bind_param('i',$uid);$stmt->execute();$alvo=$stmt->get_result()->fetch_assoc();$stmt->close();if(!$alvo)throw new RuntimeException('Usuário não encontrado.');$alvoRenan=tiPermNormalizar($alvo['usuario'])==='renan';$nome=trim((string)($_POST['nome_exibicao']??''));$email=trim((string)($_POST['email']??''));$ativo=$alvoRenan?1:(!empty($_POST['ativo'])?1:0);$adminGlobal=$alvoRenan?1:(!empty($_POST['admin_global'])?1:0);$home=trim((string)($_POST['pagina_inicial']??''));$novaSenha=(string)($_POST['nova_senha']??'');$mysqli->begin_transaction();$stmt=$mysqli->prepare('INSERT INTO ti_usuarios_config(user_id,nome_exibicao,email,ativo,admin_global,pagina_inicial,atualizado_por) VALUES(?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE nome_exibicao=VALUES(nome_exibicao),email=VALUES(email),ativo=VALUES(ativo),admin_global=VALUES(admin_global),pagina_inicial=VALUES(pagina_inicial),atualizado_por=VALUES(atualizado_por)');$stmt->bind_param('issiiss',$uid,$nome,$email,$ativo,$adminGlobal,$home,$admin);$stmt->execute();$stmt->close();if($novaSenha!==''){if(strlen($novaSenha)<8)throw new RuntimeException('A nova senha deve possuir pelo menos 8 caracteres.');$hash=password_hash($novaSenha,PASSWORD_DEFAULT);$stmt=$mysqli->prepare('UPDATE usuarios SET senha=? WHERE id=?');$stmt->bind_param('si',$hash,$uid);$stmt->execute();$stmt->close();}
   foreach($_POST['nivel']??[] as $mod=>$nivel){$f=upNivelFlags((string)$nivel);if($alvoRenan)$f=[1,1,1,1,1,1,1,1];$stmt=$mysqli->prepare('INSERT INTO ti_usuario_permissoes(user_id,modulo_slug,pode_visualizar,pode_cadastrar,pode_editar,pode_excluir,pode_transferir,pode_finalizar,pode_exportar,pode_administrar,atualizado_por) VALUES(?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE pode_visualizar=VALUES(pode_visualizar),pode_cadastrar=VALUES(pode_cadastrar),pode_editar=VALUES(pode_editar),pode_excluir=VALUES(pode_excluir),pode_transferir=VALUES(pode_transferir),pode_finalizar=VALUES(pode_finalizar),pode_exportar=VALUES(pode_exportar),pode_administrar=VALUES(pode_administrar),atualizado_por=VALUES(atualizado_por)');$stmt->bind_param('isiiiiiiiis',$uid,$mod,$f[0],$f[1],$f[2],$f[3],$f[4],$f[5],$f[6],$f[7],$admin);$stmt->execute();$stmt->close();}$mysqli->commit();tiPermRegistrarAuditoria($mysqli,'USUARIO_ATUALIZADO','usuarios_permissoes',$uid,'Perfil, status e permissões atualizados.');upFlash('sucesso','Usuário e permissões atualizados.');header('Location: usuarios_permissoes.php?editar='.$uid);exit;}
  if($acao==='salvar_matriz'){$mysqli->begin_transaction();foreach($_POST['matriz']??[] as $uid=>$mods){$uid=(int)$uid;$stmt=$mysqli->prepare('SELECT usuario FROM usuarios WHERE id=?');$stmt->bind_param('i',$uid);$stmt->execute();$urow=$stmt->get_result()->fetch_assoc();$stmt->close();$renan=$urow&&tiPermNormalizar($urow['usuario'])==='renan';foreach($mods as $mod=>$nivel){$f=$renan?[1,1,1,1,1,1,1,1]:upNivelFlags((string)$nivel);$stmt=$mysqli->prepare('INSERT INTO ti_usuario_permissoes(user_id,modulo_slug,pode_visualizar,pode_cadastrar,pode_editar,pode_excluir,pode_transferir,pode_finalizar,pode_exportar,pode_administrar,atualizado_por) VALUES(?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE pode_visualizar=VALUES(pode_visualizar),pode_cadastrar=VALUES(pode_cadastrar),pode_editar=VALUES(pode_editar),pode_excluir=VALUES(pode_excluir),pode_transferir=VALUES(pode_transferir),pode_finalizar=VALUES(pode_finalizar),pode_exportar=VALUES(pode_exportar),pode_administrar=VALUES(pode_administrar),atualizado_por=VALUES(atualizado_por)');$stmt->bind_param('isiiiiiiiis',$uid,$mod,$f[0],$f[1],$f[2],$f[3],$f[4],$f[5],$f[6],$f[7],$admin);$stmt->execute();$stmt->close();}}$mysqli->commit();tiPermRegistrarAuditoria($mysqli,'MATRIZ_ATUALIZADA','usuarios_permissoes',null,'Alteração em lote da matriz.');upFlash('sucesso','Matriz de permissões atualizada.');header('Location: usuarios_permissoes.php#matriz');exit;}
 }catch(Throwable $e){try{$mysqli->rollback();}catch(Throwable){}$erro=$e->getMessage();}
}
$flash=upGetFlash();$modulos=[];$r=$mysqli->query('SELECT * FROM ti_modulos WHERE ativo=1 ORDER BY ordem,nome');if($r)while($l=$r->fetch_assoc())$modulos[]=$l;$usuarios=[];$r=$mysqli->query('SELECT u.id,u.usuario,u.created_at,c.nome_exibicao,c.email,COALESCE(c.ativo,1) ativo,COALESCE(c.admin_global,0) admin_global,c.pagina_inicial FROM usuarios u LEFT JOIN ti_usuarios_config c ON c.user_id=u.id ORDER BY u.usuario');if($r)while($l=$r->fetch_assoc())$usuarios[]=$l;$perms=[];$r=$mysqli->query('SELECT * FROM ti_usuario_permissoes');if($r)while($l=$r->fetch_assoc())$perms[(int)$l['user_id']][$l['modulo_slug']]=$l;$editarId=(int)($_GET['editar']??0);$editar=null;foreach($usuarios as $u)if((int)$u['id']===$editarId)$editar=$u;$aud=[];$r=$mysqli->query('SELECT * FROM ti_permissoes_auditoria ORDER BY id DESC LIMIT 80');if($r)while($l=$r->fetch_assoc())$aud[]=$l;
?>
<!doctype html><html lang="pt-BR"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Usuários e Permissões</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet"><link href="governanca_style.css?v=1" rel="stylesheet"></head><body><div class="top"></div><div class="grid-bg"></div><div class="app"><header class="header"><div class="header-inner"><div class="brand"><div class="logo"><img src="assets/logo_pref.jpg" alt=""></div><div><span class="eyebrow"><i class="bi bi-person-lock"></i>Administração exclusiva • Renan</span><h1>Usuários e Permissões</h1><p>Criação de contas, bloqueio, redefinição de senha, página inicial e matriz real de acesso por módulo.</p></div></div><nav class="head-actions"><a class="head-btn" href="#matriz"><i class="bi bi-grid-3x3-gap-fill"></i>Matriz</a><a class="head-btn primary" href="governanca_ti.php"><i class="bi bi-arrow-left"></i>Governança</a></nav></div></header><main class="main"><?php if($flash):?><div class="flash <?=$flash['tipo']==='sucesso'?'success':'error'?>"><?=tiPermE($flash['mensagem'])?></div><?php endif;?><?php if($erro):?><div class="flash error"><?=tiPermE($erro)?></div><?php endif;?>
<section class="hero"><div><h2>Controle quem pode <span>ver, alterar e finalizar.</span></h2><p>A permissão é validada no servidor, inclusive quando alguém tenta digitar a URL diretamente. A Cynthia mantém uma proteção fixa: somente Painel Cynthia, Toner, Chips e Smartphones.</p><div class="tags"><span class="tag"><i class="bi bi-eye-fill"></i>Consulta</span><span class="tag"><i class="bi bi-tools"></i>Operador</span><span class="tag"><i class="bi bi-shield-lock-fill"></i>Total</span><span class="tag"><i class="bi bi-clock-history"></i>Auditoria</span></div></div><aside class="hero-side"><small>Contas cadastradas</small><strong><?=count($usuarios)?></strong><span><?=count(array_filter($usuarios,fn($u)=>(int)$u['ativo']===1))?> ativas • <?=count(array_filter($usuarios,fn($u)=>(int)$u['admin_global']===1))?> administradores globais.</span></aside></section>
<section class="panel"><div class="panel-head"><div class="panel-title"><span class="panel-icon"><i class="bi bi-people-fill"></i></span><div><h3>Usuários existentes</h3><p>Abra um usuário para alterar perfil, senha e permissões detalhadas.</p></div></div><a class="button green" href="usuarios_permissoes.php?novo=1#formulario"><i class="bi bi-person-plus-fill"></i>Novo usuário</a></div><div class="table-wrap"><table class="table"><thead><tr><th>Usuário</th><th>Status</th><th>Perfil</th><th>Página inicial</th><th>Criado em</th><th>Ações</th></tr></thead><tbody><?php foreach($usuarios as $u):?><tr><td><div class="user-chip"><span class="avatar"><?=strtoupper(substr($u['usuario'],0,2))?></span><span><span class="cell-main"><?=tiPermE($u['nome_exibicao']?:$u['usuario'])?></span><span class="cell-sub"><?=tiPermE($u['usuario'])?> • <?=tiPermE($u['email']?:'sem e-mail')?></span></span></div></td><td><span class="badge <?=(int)$u['ativo']===1?'b-green':'b-red'?>"><?=(int)$u['ativo']===1?'Ativo':'Bloqueado'?></span></td><td><span class="badge <?=(int)$u['admin_global']===1?'b-purple':'b-blue'?>"><?=(int)$u['admin_global']===1?'Administrador global':'Usuário'?></span></td><td><?=tiPermE($u['pagina_inicial']?:'Automática')?></td><td><?=date('d/m/Y',strtotime($u['created_at']))?></td><td><a class="button primary" href="usuarios_permissoes.php?editar=<?=(int)$u['id']?>#formulario">Editar</a></td></tr><?php endforeach;?></tbody></table></div></section>
<?php if(isset($_GET['novo'])||$editar):?><section class="form-card" id="formulario"><h3><i class="bi <?=$editar?'bi-person-gear':'bi-person-plus-fill'?>"></i> <?=$editar?'Editar usuário':'Criar novo usuário'?></h3><form method="post" style="margin-top:14px"><input type="hidden" name="csrf_token" value="<?=tiPermE($csrf)?>"><input type="hidden" name="acao" value="<?=$editar?'atualizar_usuario':'criar_usuario'?>"><?php if($editar):?><input type="hidden" name="user_id" value="<?=(int)$editar['id']?>"><?php endif;?><div class="form-grid"><?php if(!$editar):?><div class="form-group"><label>Login *</label><input class="control" name="usuario" required maxlength="50"></div><div class="form-group"><label>Senha inicial *</label><input class="control" type="password" name="senha" required minlength="8"></div><?php else:?><div class="form-group"><label>Login</label><input class="control" value="<?=tiPermE($editar['usuario'])?>" disabled></div><div class="form-group"><label>Nova senha</label><input class="control" type="password" name="nova_senha" minlength="8" placeholder="Deixe vazio para preservar"></div><?php endif;?><div class="form-group"><label>Nome de exibição</label><input class="control" name="nome_exibicao" value="<?=tiPermE($editar['nome_exibicao']??'')?>"></div><div class="form-group"><label>E-mail</label><input class="control" type="email" name="email" value="<?=tiPermE($editar['email']??'')?>"></div><div class="form-group"><label>Página inicial</label><select class="control" name="pagina_inicial"><option value="">Automática conforme permissões</option><?php foreach(['listar_os.php'=>'Ordens de serviço','governanca_ti.php'=>'Governança TI','central_ativos.php'=>'Central de Ativos','inventario_geral.php'=>'Inventário Geral','dashboard_cynthia.php'=>'Painel Cynthia','tonner.php'=>'Toner','impressoras.php'=>'Impressoras'] as $rota=>$rot):?><option value="<?=$rota?>" <?=($editar['pagina_inicial']??'')===$rota?'selected':''?>><?=$rot?></option><?php endforeach;?></select></div><div class="form-group"><label style="padding-top:24px;display:flex;gap:8px;align-items:center"><input type="checkbox" name="ativo" value="1" <?=!$editar||(int)$editar['ativo']===1?'checked':''?>> Conta ativa</label></div><?php if($editar&&tiPermNormalizar($editar['usuario'])!=='renan'):?><div class="form-group"><label style="padding-top:24px;display:flex;gap:8px;align-items:center"><input type="checkbox" name="admin_global" value="1" <?=(int)$editar['admin_global']===1?'checked':''?>> Administrador global</label></div><?php endif;?></div><h3 style="margin-top:20px">Nível por módulo</h3><div class="form-grid" style="margin-top:10px"><?php foreach($modulos as $m):?><?php $p=$editar?($perms[(int)$editar['id']][$m['slug']]??[]):[];$nivel=$p?upNivelAtual($p):'sem';?><div class="form-group"><label><?=tiPermE($m['nome'])?></label><select class="control" name="nivel[<?=tiPermE($m['slug'])?>]"><option value="sem" <?=$nivel==='sem'?'selected':''?>>Sem acesso</option><option value="consulta" <?=$nivel==='consulta'?'selected':''?>>Consulta</option><option value="operador" <?=$nivel==='operador'?'selected':''?>>Operador</option><option value="total" <?=$nivel==='total'?'selected':''?>>Total</option></select></div><?php endforeach;?></div><div class="alert warn" style="margin-top:14px"><strong>Cynthia:</strong> a proteção fixa do sistema continua limitando a conta aos módulos autorizados, mesmo que alguém marque outra permissão por engano.</div><div class="actions"><a class="button" href="usuarios_permissoes.php">Cancelar</a><button class="button green"><i class="bi bi-check-circle-fill"></i><?=$editar?'Salvar alterações':'Criar usuário'?></button></div></form></section><?php endif;?>
<section class="panel" id="matriz"><div class="panel-head"><div class="panel-title"><span class="panel-icon"><i class="bi bi-grid-3x3-gap-fill"></i></span><div><h3>Matriz real de permissões</h3><p>Consulta: somente leitura. Operador: rotina completa sem excluir ou administrar. Total: todas as ações.</p></div></div></div><form method="post"><input type="hidden" name="csrf_token" value="<?=tiPermE($csrf)?>"><input type="hidden" name="acao" value="salvar_matriz"><div class="table-wrap"><table class="table" style="min-width:1800px"><thead><tr><th>Usuário</th><?php foreach($modulos as $m):?><th><?=tiPermE($m['nome'])?></th><?php endforeach;?></tr></thead><tbody><?php foreach($usuarios as $u):?><tr><td><span class="cell-main"><?=tiPermE($u['usuario'])?></span><span class="cell-sub"><?=(int)$u['ativo']===1?'Ativo':'Bloqueado'?></span></td><?php foreach($modulos as $m):?><?php $p=$perms[(int)$u['id']][$m['slug']]??[];$nivel=tiPermNormalizar($u['usuario'])==='renan'?'total':($p?upNivelAtual($p):'sem');?><td class="matrix-cell"><select class="control" name="matriz[<?=(int)$u['id']?>][<?=tiPermE($m['slug'])?>]" <?=tiPermNormalizar($u['usuario'])==='renan'?'disabled':''?>><option value="sem" <?=$nivel==='sem'?'selected':''?>>Sem acesso</option><option value="consulta" <?=$nivel==='consulta'?'selected':''?>>Consulta</option><option value="operador" <?=$nivel==='operador'?'selected':''?>>Operador</option><option value="total" <?=$nivel==='total'?'selected':''?>>Total</option></select><?php if(tiPermNormalizar($u['usuario'])==='renan'):?><input type="hidden" name="matriz[<?=(int)$u['id']?>][<?=tiPermE($m['slug'])?>]" value="total"><?php endif;?></td><?php endforeach;?></tr><?php endforeach;?></tbody></table></div><div class="actions" style="padding:0 18px 18px"><button class="button primary"><i class="bi bi-save-fill"></i>Salvar matriz completa</button></div></form></section>
<section class="panel"><div class="panel-head"><div class="panel-title"><span class="panel-icon"><i class="bi bi-clock-history"></i></span><div><h3>Auditoria administrativa</h3><p>Últimas alterações, criações e tentativas de acesso negadas.</p></div></div></div><div class="table-wrap"><table class="table"><thead><tr><th>Data</th><th>Usuário</th><th>Ação</th><th>Módulo</th><th>Detalhes</th><th>IP</th></tr></thead><tbody><?php foreach($aud as $a):?><tr><td><?=date('d/m/Y H:i',strtotime($a['criado_em']))?></td><td><?=tiPermE($a['usuario'])?></td><td><?=tiPermE($a['acao'])?></td><td><?=tiPermE($a['modulo_slug'])?></td><td><?=tiPermE($a['detalhes'])?></td><td><?=tiPermE($a['ip'])?></td></tr><?php endforeach;?></tbody></table></div></section></main></div></body></html>
