Admin sekce.
parent
7a98fb3f53
commit
3688c0312d
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Facade;
|
||||
|
||||
use Nette\Database\Connection;
|
||||
|
||||
class DatabazeFacade
|
||||
{
|
||||
public function __construct(
|
||||
private Connection $masterDb
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Seznam databází z master tabulky LOGIN (jeden login = jedna databáze).
|
||||
*
|
||||
* @return \Nette\Database\Row[]
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return $this->masterDb->fetchAll(
|
||||
'SELECT ID, EMAIL, POSLEDNI_PRIHLASENI, AKTIVNI, [DATABASE], [SERVER], FIRMA_ID, IS_ADMIN
|
||||
FROM dbo.LOGIN
|
||||
ORDER BY [DATABASE], EMAIL'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ class Authenticator implements IAuthenticator
|
|||
|
||||
// 1. Načtení uživatele podle tvého přesného schématu UZIVATEL
|
||||
$row = $this->masterDb->fetch(
|
||||
'SELECT ID, EMAIL, HESLO_HASH, [DATABASE], [SERVER], FIRMA_ID
|
||||
'SELECT ID, EMAIL, HESLO_HASH, [DATABASE], [SERVER], FIRMA_ID, IS_ADMIN
|
||||
FROM dbo.LOGIN
|
||||
WHERE EMAIL = ? AND AKTIVNI = 1',
|
||||
$email
|
||||
|
|
@ -57,14 +57,17 @@ class Authenticator implements IAuthenticator
|
|||
//$firmaId = $firmaRow ? $firmaRow->FIRMA_ID : $row->ID;
|
||||
|
||||
// 4. Předání dat do Nette Identity
|
||||
$isAdmin = (bool) $row->IS_ADMIN;
|
||||
|
||||
return new SimpleIdentity(
|
||||
$row->ID,
|
||||
null, // role
|
||||
$isAdmin ? 'admin' : 'user',
|
||||
[
|
||||
'email' => $row->EMAIL,
|
||||
'database' => $row->DATABASE, // Nulllable -> KufrikConnectionFactory použije default_db
|
||||
'server' => $row->SERVER,
|
||||
'firma_id' => (int) $row->FIRMA_ID, // Zpřístupní $user->identity->firma_id
|
||||
'is_admin' => $isAdmin,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@
|
|||
<i class="bi bi-box me-1"></i> Kufřík
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<!-- ADMIN — pouze systémový administrátor -->
|
||||
{if $user->isInRole('admin')}
|
||||
<li class="nav-item" role="presentation">
|
||||
<button n:class="nav-link, $presenter->isLinkCurrent('Admin:*') ? active"
|
||||
id="cat-admin-tab" data-bs-toggle="tab" data-bs-target="#toolbar-admin" type="button" role="tab">
|
||||
<i class="bi bi-shield-lock me-1"></i> Admin
|
||||
</button>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
|
|
@ -214,6 +224,22 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ADMIN -->
|
||||
{if $user->isInRole('admin')}
|
||||
<div n:class="tab-pane, fade, $presenter->isLinkCurrent('Admin:*') ? 'show active'" id="toolbar-admin" role="tabpanel">
|
||||
<div class="action-buttons">
|
||||
<a n:href="Admin:databaze" n:class="btn, btn-action, $presenter->isLinkCurrent('Admin:databaze') ? 'btn-primary active' : 'btn-outline-primary'">
|
||||
<i class="bi bi-database-fill"></i>
|
||||
<span>Databáze</span>
|
||||
</a>
|
||||
<a n:href="Admin:statistika" n:class="btn, btn-action, $presenter->isLinkCurrent('Admin:statistika') ? 'btn-primary active' : 'btn-outline-primary'">
|
||||
<i class="bi bi-graph-up"></i>
|
||||
<span>Statistika</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\UI\Admin;
|
||||
|
||||
use App\Model\Facade\DatabazeFacade;
|
||||
use App\UI\BasePresenter;
|
||||
|
||||
class AdminPresenter extends BasePresenter
|
||||
{
|
||||
public function __construct(
|
||||
private DatabazeFacade $databazeFacade
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function startup(): void
|
||||
{
|
||||
parent::startup();
|
||||
|
||||
if (!$this->getUser()->isInRole('admin')) {
|
||||
$this->error('Sekce Admin je dostupná pouze administrátorovi systému.', 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function actionDefault(): void
|
||||
{
|
||||
$this->redirect('databaze');
|
||||
}
|
||||
|
||||
public function renderDatabaze(): void
|
||||
{
|
||||
$loginy = $this->databazeFacade->getAll();
|
||||
$aktivniCount = 0;
|
||||
|
||||
foreach ($loginy as $login) {
|
||||
if ($login->AKTIVNI) {
|
||||
$aktivniCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->template->loginy = $loginy;
|
||||
$this->template->celkemCount = count($loginy);
|
||||
$this->template->aktivniCount = $aktivniCount;
|
||||
}
|
||||
|
||||
public function renderStatistika(): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
{block content}
|
||||
|
||||
<!-- DataTables CSS s Bootstrap 5 vzhledem -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.6/css/dataTables.bootstrap5.min.css">
|
||||
|
||||
<div class="container-fluid py-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h2 class="h3 mb-0">Přehled databází</h2>
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mb-4">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card border-0 shadow-sm p-3 bg-white border-start border-primary border-4">
|
||||
<div class="text-muted small">Celkem databází</div>
|
||||
<div class="fs-4 fw-bold text-primary">{$celkemCount} ks</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card border-0 shadow-sm p-3 bg-white border-start border-success border-4">
|
||||
<div class="text-muted small">Aktivní</div>
|
||||
<div class="fs-4 fw-bold text-success">{$aktivniCount} ks</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0 p-3 bg-white">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle w-100" id="databaze-table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Databáze</th>
|
||||
<th>Server</th>
|
||||
<th>Login</th>
|
||||
<th class="text-center">Firma ID</th>
|
||||
<th>Poslední přihlášení</th>
|
||||
<th class="text-center">Stav</th>
|
||||
<th class="text-center">Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $loginy as $login}
|
||||
<tr n:class="!$login->AKTIVNI ? 'table-light text-muted'">
|
||||
<td class="fw-bold" data-order="{$login->DATABASE}">
|
||||
<i class="bi bi-database me-1 text-muted"></i>{$login->DATABASE}
|
||||
</td>
|
||||
<td>{$login->SERVER}</td>
|
||||
<td>
|
||||
<a href="mailto:{$login->EMAIL}" class="text-decoration-none">{$login->EMAIL}</a>
|
||||
</td>
|
||||
<td class="text-center">{$login->FIRMA_ID}</td>
|
||||
<td data-order="{if $login->POSLEDNI_PRIHLASENI}{$login->POSLEDNI_PRIHLASENI|date:'YmdHis'}{/if}">
|
||||
{if $login->POSLEDNI_PRIHLASENI}
|
||||
{$login->POSLEDNI_PRIHLASENI|date:'d.m.Y H:i'}
|
||||
{else}
|
||||
<span class="text-muted">—</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-center" data-order="{$login->AKTIVNI}">
|
||||
{if $login->AKTIVNI}
|
||||
<span class="badge bg-success">Aktivní</span>
|
||||
{else}
|
||||
<span class="badge bg-secondary">Neaktivní</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-center" data-order="{$login->IS_ADMIN}">
|
||||
{if $login->IS_ADMIN}
|
||||
<span class="badge bg-dark">Admin</span>
|
||||
{else}
|
||||
<span class="badge bg-light text-dark border">Uživatel</span>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/datatables.net@1.13.6/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/datatables.net-bs5@1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
||||
|
||||
{syntax off}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#databaze-table').DataTable({
|
||||
language: {
|
||||
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/cs.json'
|
||||
},
|
||||
order: [[0, 'asc']],
|
||||
pageLength: 25
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/syntax}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{block content}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="content-card my-3">
|
||||
<h2 class="h4 mb-3" style="color: var(--header-bg);">
|
||||
<i class="bi bi-graph-up me-2"></i>Statistika
|
||||
</h2>
|
||||
<hr style="border-color: var(--border-color); margin-bottom: 1.5rem;">
|
||||
<p class="text-muted mb-0">Systémové statistiky budou doplněny.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -6,6 +6,9 @@ services:
|
|||
# Authenticator si vyžádá připojení k Master DB
|
||||
- App\Model\Security\Authenticator(@database.default.connection)
|
||||
|
||||
# Seznam databází (LOGIN) z Master DB
|
||||
- App\Model\Facade\DatabazeFacade(@database.default.connection)
|
||||
|
||||
# 1. Factory pro klientskou databázi
|
||||
kufrikConnectionFactory:
|
||||
factory: App\Model\Database\KufrikConnectionFactory(%clientDb.user%, %clientDb.password%)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ BEGIN
|
|||
[DATABASE] [nvarchar](128) NOT NULL,
|
||||
[SERVER] [nvarchar](100) NOT NULL,
|
||||
[FIRMA_ID] [int] NOT NULL, -- vazna na tabulku FIRMA v datové DB
|
||||
[IS_ADMIN] [bit] NOT NULL CONSTRAINT [DF_LOGIN_IS_ADMIN] DEFAULT 0,
|
||||
|
||||
CONSTRAINT [PK_LOGIN] PRIMARY KEY CLUSTERED ([ID] ASC),
|
||||
CONSTRAINT [UQ_LOGIN_EMAIL] UNIQUE NONCLUSTERED ([EMAIL] ASC)
|
||||
|
|
@ -58,7 +59,8 @@ INSERT INTO dbo.[LOGIN] (
|
|||
[HESLO_HASH],
|
||||
[DATABASE],
|
||||
[SERVER],
|
||||
[FIRMA_ID]
|
||||
[FIRMA_ID],
|
||||
[IS_ADMIN]
|
||||
)
|
||||
VALUES (
|
||||
1,
|
||||
|
|
@ -67,11 +69,20 @@ VALUES (
|
|||
N'$2y$12$9SAWctZKp/JpYl7K.awSRehXOXVyRpu0ofReqvbm1jVjvdz41zH7a',
|
||||
N'kufrik',
|
||||
N'localhost',
|
||||
1 -- Odkaz na FIRMA.ID = 1 v klientské databázi 'kufrik'
|
||||
1, -- Odkaz na FIRMA.ID = 1 v klientské databázi 'kufrik'
|
||||
1 -- systémový administrátor
|
||||
);
|
||||
SET IDENTITY_INSERT dbo.[LOGIN] OFF;
|
||||
GO
|
||||
|
||||
-- Existující instalace: sloupec IS_ADMIN
|
||||
IF COL_LENGTH('dbo.LOGIN', 'IS_ADMIN') IS NULL
|
||||
BEGIN
|
||||
ALTER TABLE dbo.LOGIN ADD [IS_ADMIN] [bit] NOT NULL CONSTRAINT [DF_LOGIN_IS_ADMIN] DEFAULT 0;
|
||||
UPDATE dbo.LOGIN SET [IS_ADMIN] = 1 WHERE [EMAIL] = N'admin@kmetix.cz';
|
||||
END
|
||||
GO
|
||||
|
||||
-- ==========================================
|
||||
-- DATOVÁ databáze
|
||||
-- ==========================================
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
USE [kufrik_master]
|
||||
GO
|
||||
|
||||
IF COL_LENGTH('dbo.LOGIN', 'IS_ADMIN') IS NULL
|
||||
BEGIN
|
||||
ALTER TABLE dbo.LOGIN ADD [IS_ADMIN] [bit] NOT NULL CONSTRAINT [DF_LOGIN_IS_ADMIN] DEFAULT 0;
|
||||
UPDATE dbo.LOGIN SET [IS_ADMIN] = 1 WHERE [EMAIL] = N'admin@kmetix.cz';
|
||||
END
|
||||
GO
|
||||
Loading…
Reference in New Issue