# LGPD (Barra de Privacidade) — Rotas e Controladores

> **Versão analisada:** `v6`
> **Slug do módulo:** `lgpd`

---

## 1. Rotas do CMS (`v6/routes/basepro.php`, prefixo `cms`, `before: csrf`)

| Linha | Método | URI | Nome (`->name()`) | Controller@ação | Middleware |
|---|---|---|---|---|---|
| 241 | GET | `/cms/configuracoes/editar/{slug}` | `edit.configuracoes.by.category` | `Prefecture\ConfigurationController@editByCategory` | `check.logged` |
| 246 | POST | `/cms/update/configuration` | `update.configurations.by.category` | `Prefecture\ConfigurationController@updateByCategory` | **sem** `check.logged` (guarda interna por `has_access`) |
| 175 | resource | `/cms/configuracoes` (+ `/{id}`) | `configuracoes.index`, `.create`, `.store`, `.show`, `.edit`, `.update`, `.destroy` | `Prefecture\ConfigurationController` | `check.logged` |
| 451 | GET | `/cms/datatable/configuracoes` | `datatable.configuracoes` | `Prefecture\DatatableController@get_configuracoes` | — |

Trecho real das rotas (`v6/routes/basepro.php:241` e `:246`):

```php
Route::get('configuracoes/editar/{slug}', ['uses' => 'Prefecture\ConfigurationController@editByCategory'])->name('edit.configuracoes.by.category')->middleware('check.logged');

Route::post('update/configuration', 'Prefecture\ConfigurationController@updateByCategory')->name('update.configurations.by.category');
```

Para a LGPD, a rota é chamada com `{slug} = 'barra-privacidade'`:

```php
<a href="{{ route('edit.configuracoes.by.category', 'barra-privacidade') }}">
```

### Rota do CMS que ativa/desativa o módulo

| Linha | Método | URI | Nome | Controller@ação |
|---|---|---|---|---|
| 37 | GET | `/cms/modulos` | `modulos.index` | `Admin\ModulosController@index` |
| 38 | POST | `/cms/modulos` | `modulos.update` | `Admin\ModulosController@update` |

`v6/app/Http/Controllers/Admin/ModulosController.php` faz `Cache::pull('modulos')`
ao salvar (invalidando o cache usado pelo `ModulosServiceProvider`) e grava
`structure_type` para o perfil prefeitura/câmara.

## 2. Rotas públicas (`v6/routes/web.php`)

| Linha | Método | URI | Nome | Controller@ação |
|---|---|---|---|---|
| 208 | GET | `/getPrivacyBar` | `get-privacy-bar` | `Portal\HelperController@getPrivacyBar` |
| 207 | GET | `/getColors` | `get-colors` | `Portal\HelperController@getColors` |
| 5 | GET | `/selos` | `selos.index` | `Portal\SelosController@index` |

Trecho real (`v6/app/Http/Controllers/Portal/HelperController.php`):

```php
public function getPrivacyBar()
{
    return Configuration::where('key', 'barra-privacidade-expiracao')->orderBy('id')->first(['key', 'value']);
}
```

Resposta JSON esperada (serialização do model, apenas `key` e `value`):

```json
{"key":"barra-privacidade-expiracao","value":"7"}
```

> O endpoint é público, sem autenticação e sem rate limit: expõe apenas o prazo
> de expiração (informação não sensível).

## 3. Controladores

### 3.1 `Prefecture\ConfigurationController`

Arquivo: `v6/app/Http/Controllers/Prefecture/ConfigurationController.php` (856 linhas).
Não há método dedicado à LGPD; o módulo é atendido pelo `switch` sobre `$slug`.

`editByCategory(string $slug)` (≈ linhas 421-520):

```php
$reference = $acess = $slug;

if ($slug == 'configuracoes')
    $reference = "site";
if ($slug == 'temas')
    $acess = 'tema-do-portal';

$configurations = $this->getConfiguration($reference);

$category = CategoryConfiguration::where('slug', $reference)->first();
$states = DB::table('states')->get();

if (!has_access(["$acess.edit"])) {
    flash('Você não tem permissão para acessar este conteúdo')->warning();
    return redirect()->route('dashboard.index');
}

switch ($slug) {
    // demais cases omitidos
    case 'barra-privacidade':
        $title = 'LGPD';
        $this->configurationLog('Acessou edição de barra de privacidade');
        return view("prefecture.configurations.{$slug}.edit", compact("configurations", 'title', 'category'));
    // demais cases omitidos
}
```

Para `slug = 'barra-privacidade'`: `$reference = 'barra-privacidade'` e
`$acess = 'barra-privacidade'` → permissão exigida na leitura:
**`barra-privacidade.edit`**.

`updateByCategory(ConfigurationRequest $request)` (≈ linhas 227-420):

```php
public function updateByCategory(ConfigurationRequest $request): RedirectResponse
{
    if (!has_access(['configuracoes.edit'])) {
        flash('Você não tem permissão para salvar')->warning();
        return redirect()->route('dashboard.index');
    }

    $category = CategoryConfiguration::find($request->get('category_configurations_id'));
    $dataForm = $request->except('_token', 'category_configurations_id', 'display');
    // trecho intermediário omitido
    foreach ($dataForm as $key => $value) {
        $config = Configuration::where('key', $key)->first();
        if (!$config) continue;
        // tratamento de upload de arquivo omitido
        $config->value = $value;
        $config->save();
        activity()->performedOn($config)
            ->causedBy(Sentinel::getUser())
            ->withProperty('Detalhe', 'Foi atualizada uma configuração: Id:' . $config->id . ',Chave:' . $config->key . ',Valor:' . $config->value . ',Tipo:' . $config->type)
            ->log('Edição de configuração');
        Cache::pull('structureType');
    }

    flash('Configurações salvas com sucesso')->success();
    // ramo de redirecionamento conforme a categoria
    return redirect()->route("edit.configuracoes.by.category", $category->slug)->with('display', $request->display);
}
```

Pontos relevantes para a LGPD:

- A gravação exige **sempre** `configuracoes.edit` — a mesma permissão dos outros
  três módulos (assimetria em relação à leitura).
- O `category_configurations_id` vem do campo hidden do formulário
  (`{{$category->id}}`); **não é validado contra o conteúdo enviado** — um POST
  forjado com outro `category_configurations_id` gravaria as chaves de outra
  categoria.
- O `switch` do controller tem um único `foreach` que grava **todas** as
  categorias num único endpoint: a separação entre LGPD e as demais categorias
  é apenas o `category_configurations_id` enviado.
- O log de atividade registra chave e valor alterado (o texto HTML da barra
  fica no log).

### 3.2 `Portal\HelperController`

Arquivo: `v6/app/Http/Controllers/Portal/HelperController.php`.
Único método usado pela LGPD: `getPrivacyBar()` (mostrado na seção 2).

### 3.3 `Admin\ModulosController`

Arquivo: `v6/app/Http/Controllers/Admin/ModulosController.php`.
Gerencia o `status` de `modulos.slug = 'lgpd'` (liga/desliga a barra) e
invalida o cache `modulos`.

## 4. Form Request / validação

Arquivo: `v6/app/Http/Requests/ConfigurationRequest.php`.

- `authorize()`: retorna `true` sempre — a autorização real está no controller.
- `rules()`: quando a rota atual é `update.configurations.by.category`, as regras
  são **geradas dinamicamente**, uma query ao banco **por campo enviado**:

```php
if (Route::getCurrentRoute()->getName() == "update.configurations.by.category") {
    $dataForm = $request->except('_token');
    $size = count($dataForm);
    $keys = array_keys($dataForm);
    $rules = [];
    for ( $i = 0; $i < $size; $i++) {
        $config = Configuration::where('key', $keys[$i])->first();
        if (!empty($config)) {
            if ($config->notnull == true) {
                $required = 'required';
                if ($config->max_input != ''){
                    $max = '|max:'.$config->max_input."|";
                } else { $max = ''; }
                if ($config->max_input != ''){
                    $min = '|min:'.$config->min_input.'';
                } else { $min = ''; }
            } else {
                $required = ''; $max = ''; $min = '';
            }
        }
        $rules += [ $keys[$i] => $required.$max.$min];
    }
```

Efeito prático no módulo LGPD (as 4 chaves têm `notnull = false`):

| Campo enviado | Regra gerada | Observação |
|---|---|---|
| `barra-privacidade` | `''` (nenhuma) | Texto livre; HTML do Summernote passa sem validação. |
| `barra-privacidade-expiracao` | `''` | Sem validação numérica, apesar de `min_input = 1` / `max_input = 999`. |
| `barra-privacidade-exibir` | `''` | Checkbox envia `0` ou `1`. |
| `barra-privacidade-botao` | `''` | Aceita qualquer texto (inclusive valor inválido de cor). |
| `category_configurations_id` | nãoGerada (cai no `''` da iteração) | Na prática só é verificado `find()` no controller. |

- `messages()`: também monta mensagens por campo com uma query por chave.

## 5. API Resources / presenters

Não existem API Resources para a LGPD. A resposta de `/getPrivacyBar` é a
serialização direta do model Eloquent (`key`, `value`), sem classe de
apresentação.

## 6. Permissões exigidas

| Contexto | Verificação | Helper |
|---|---|---|
| Leitura da tela do CMS | `has_access(["barra-privacidade.edit"])` | `v6/app/Library/Helper/appHelpers.php:22` (`has_access`) |
| Gravação | `has_access(['configuracoes.edit'])` | idem |
| Item de menu do CMS | `has_access(['barra-privacidade.index'])` **e** `$modulos['lgpd']` | `v6/resources/views/vendor/adminlte/page.blade.php:244` |

Regras do helper `has_access()`:

```php
// false se não há login; true para o papel 'super-admin';
// caso contrário: Sentinel::check()->hasAnyAccess($access)  (array)
// ou hasAccess([$access]) (string)
```

O middleware `v6/app/Http/Middleware/CheckRoutePermission.php` mapeia verbos
(`edit`→`update`, `create`→`store`, `delete`→`destroy`) para as permissões do
recurso `barra-privacidade` — mas **não** é aplicado às rotas deste módulo
(que usam `check.logged`).

## 7. Separação CMS / Portal / API

| Camada | Rotas | Autenticação |
|---|---|---|
| CMS | `/cms/configuracoes/editar/barra-privacidade`, `/cms/update/configuration` | `check.logged` na leitura; `has_access` no controller |
| Portal | páginas do portal (`modelo1..modelo6`) | pública |
| API/helper | `/getPrivacyBar` | pública |

## 8. Itens do menu do CMS (linha 244 de `v6/resources/views/vendor/adminlte/page.blade.php`)

```blade
@if (has_access(['barra-privacidade.index']) && $modulos['lgpd'])
    <li>
        <a href="{{ route('edit.configuracoes.by.category', 'barra-privacidade') }}">
            <h4 class="ml-0">
                <i class="fa fa-shield pr-2"></i>
                LGPD
            </h4>
        </a>
    </li>
@endif
```

> Com `modulos.status = 0` para `lgpd`, o item **nunca** aparece no menu do CMS,
> mesmo para super-admin. O módulo só fica acessível por URL direta.
