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
|
// 1. Načtení uživatele podle tvého přesného schématu UZIVATEL
|
||||||
$row = $this->masterDb->fetch(
|
$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
|
FROM dbo.LOGIN
|
||||||
WHERE EMAIL = ? AND AKTIVNI = 1',
|
WHERE EMAIL = ? AND AKTIVNI = 1',
|
||||||
$email
|
$email
|
||||||
|
|
@ -57,14 +57,17 @@ class Authenticator implements IAuthenticator
|
||||||
//$firmaId = $firmaRow ? $firmaRow->FIRMA_ID : $row->ID;
|
//$firmaId = $firmaRow ? $firmaRow->FIRMA_ID : $row->ID;
|
||||||
|
|
||||||
// 4. Předání dat do Nette Identity
|
// 4. Předání dat do Nette Identity
|
||||||
|
$isAdmin = (bool) $row->IS_ADMIN;
|
||||||
|
|
||||||
return new SimpleIdentity(
|
return new SimpleIdentity(
|
||||||
$row->ID,
|
$row->ID,
|
||||||
null, // role
|
$isAdmin ? 'admin' : 'user',
|
||||||
[
|
[
|
||||||
'email' => $row->EMAIL,
|
'email' => $row->EMAIL,
|
||||||
'database' => $row->DATABASE, // Nulllable -> KufrikConnectionFactory použije default_db
|
'database' => $row->DATABASE, // Nulllable -> KufrikConnectionFactory použije default_db
|
||||||
'server' => $row->SERVER,
|
'server' => $row->SERVER,
|
||||||
'firma_id' => (int) $row->FIRMA_ID, // Zpřístupní $user->identity->firma_id
|
'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
|
<i class="bi bi-box me-1"></i> Kufřík
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
@ -214,6 +224,22 @@
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
</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
|
# Authenticator si vyžádá připojení k Master DB
|
||||||
- App\Model\Security\Authenticator(@database.default.connection)
|
- 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
|
# 1. Factory pro klientskou databázi
|
||||||
kufrikConnectionFactory:
|
kufrikConnectionFactory:
|
||||||
factory: App\Model\Database\KufrikConnectionFactory(%clientDb.user%, %clientDb.password%)
|
factory: App\Model\Database\KufrikConnectionFactory(%clientDb.user%, %clientDb.password%)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ BEGIN
|
||||||
[DATABASE] [nvarchar](128) NOT NULL,
|
[DATABASE] [nvarchar](128) NOT NULL,
|
||||||
[SERVER] [nvarchar](100) NOT NULL,
|
[SERVER] [nvarchar](100) NOT NULL,
|
||||||
[FIRMA_ID] [int] NOT NULL, -- vazna na tabulku FIRMA v datové DB
|
[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 [PK_LOGIN] PRIMARY KEY CLUSTERED ([ID] ASC),
|
||||||
CONSTRAINT [UQ_LOGIN_EMAIL] UNIQUE NONCLUSTERED ([EMAIL] ASC)
|
CONSTRAINT [UQ_LOGIN_EMAIL] UNIQUE NONCLUSTERED ([EMAIL] ASC)
|
||||||
|
|
@ -58,7 +59,8 @@ INSERT INTO dbo.[LOGIN] (
|
||||||
[HESLO_HASH],
|
[HESLO_HASH],
|
||||||
[DATABASE],
|
[DATABASE],
|
||||||
[SERVER],
|
[SERVER],
|
||||||
[FIRMA_ID]
|
[FIRMA_ID],
|
||||||
|
[IS_ADMIN]
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
1,
|
1,
|
||||||
|
|
@ -67,11 +69,20 @@ VALUES (
|
||||||
N'$2y$12$9SAWctZKp/JpYl7K.awSRehXOXVyRpu0ofReqvbm1jVjvdz41zH7a',
|
N'$2y$12$9SAWctZKp/JpYl7K.awSRehXOXVyRpu0ofReqvbm1jVjvdz41zH7a',
|
||||||
N'kufrik',
|
N'kufrik',
|
||||||
N'localhost',
|
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;
|
SET IDENTITY_INSERT dbo.[LOGIN] OFF;
|
||||||
GO
|
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
|
-- 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