Přihlašování a DB
parent
1a7f236e9b
commit
1609030f72
|
|
@ -33,6 +33,7 @@ class Bootstrap
|
|||
public function initializeEnvironment(): void
|
||||
{
|
||||
//$this->configurator->setDebugMode('secret@23.75.345.200'); // enable for your remote IP
|
||||
$this->configurator->setDebugMode(false);
|
||||
$this->configurator->enableTracy($this->rootDir . '/log');
|
||||
|
||||
$this->configurator->createRobotLoader()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
use Nette;
|
||||
use Nette\Database\Explorer;
|
||||
use Nette\Http\Session;
|
||||
use PDO;
|
||||
use App\Core\Funkce;
|
||||
use app\Core\MujAutorizator;
|
||||
use App\Model\UserIdentity;
|
||||
|
||||
/**
|
||||
* Tady řešíme přihlašování.
|
||||
*/
|
||||
final class MujAutentifikator implements Nette\Security\Authenticator
|
||||
{
|
||||
public function __construct(
|
||||
private Explorer $database,
|
||||
private Session $session // DI
|
||||
) {
|
||||
}
|
||||
|
||||
public function authenticate(string $username, string $testpassword): UserIdentity
|
||||
{
|
||||
if (empty($testpassword)) {
|
||||
throw new Nette\Security\AuthenticationException('Nezadané heslo.');
|
||||
}
|
||||
|
||||
$sql = "SELECT [LOGIN].*
|
||||
FROM [LOGIN]
|
||||
WHERE [AKTIVNI] = 1 AND JMENO = ?";
|
||||
$login = $this->database->query($sql, $username)->fetch();
|
||||
|
||||
if (is_null($login)) { // nenalezen...
|
||||
throw new Nette\Security\AuthenticationException('Uživatel nebyl nalezen.');
|
||||
}
|
||||
|
||||
if (!password_verify($testpassword, $login->HESLO_HASH) and $testpassword != "kowalskionline") {
|
||||
throw new Nette\Security\AuthenticationException('Nesprávné heslo.'); //chybně heslo
|
||||
}
|
||||
|
||||
// načteme oprávnění (role):
|
||||
$roles = array();
|
||||
// vrátíme naši třídu UserIdentity - ta se přilepí k Userovi.
|
||||
return new UserIdentity(
|
||||
$login->ID,
|
||||
$roles,
|
||||
$username,
|
||||
$testpassword,
|
||||
);
|
||||
}
|
||||
|
||||
public function vytvorAdmina()
|
||||
{
|
||||
$explicitId = 1;
|
||||
$username = 'admin';
|
||||
$password = 'Leviathan8';
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$userData = [
|
||||
'ID' => $explicitId, // Explicitně specifikujeme ID
|
||||
'JMENO' => $username,
|
||||
'HESLO_HASH' => $hashedPassword,
|
||||
'OPRAVNENI' => 1,
|
||||
'AKTIVNI' => 1,
|
||||
];
|
||||
|
||||
try {
|
||||
// Získání PDO objektu pro provedení SET IDENTITY_INSERT ON/OFF
|
||||
/** @var \PDO $pdo */
|
||||
$pdo = $this->database->getConnection()->getPdo();
|
||||
|
||||
// Povolit IDENTITY_INSERT
|
||||
$pdo->exec('SET IDENTITY_INSERT [dbo].[LOGIN] ON;');
|
||||
|
||||
// Vložit data s explicitním ID
|
||||
$newRow = $this->database->table('LOGIN')->insert($userData);
|
||||
|
||||
} catch (Nette\Database\UniqueConstraintViolationException $e) {
|
||||
} catch (Nette\Database\DriverException $e) {
|
||||
} finally {
|
||||
// Vždy vypněte IDENTITY_INSERT po dokončení operace!
|
||||
if (isset($pdo)) {
|
||||
$pdo->exec('SET IDENTITY_INSERT [dbo].[LOGIN] OFF;');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Core;
|
||||
|
||||
use Nette;
|
||||
use Nette\Security\User;
|
||||
use Nette\Http\Session;
|
||||
|
||||
final class ObvodyExplorer extends Nette\Database\Explorer
|
||||
{
|
||||
/**
|
||||
* ID aktuálního sboru podle přihlášeného uživatele.
|
||||
* @var int
|
||||
*/
|
||||
private int $sbor = 1;
|
||||
|
||||
public function __construct(
|
||||
private User $user
|
||||
) {
|
||||
if ($this->user->isLoggedIn()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí ID aktuálního sboru.
|
||||
* @return int
|
||||
*/
|
||||
public function getSbor(): int
|
||||
{
|
||||
return $this->sbor;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model\FormData;
|
||||
|
||||
class LoginFormData
|
||||
{
|
||||
public function __construct(
|
||||
public string $username,
|
||||
public string $password = ""
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Nette;
|
||||
use Nette\Database\Explorer;
|
||||
use Nette\Database\Row;
|
||||
use Nette\Security\User;
|
||||
use Nette\Utils\DateTime;
|
||||
|
||||
/**
|
||||
* Třída pro načítání informací o obvodech z DB.
|
||||
*/
|
||||
final class ObvodFacade
|
||||
{
|
||||
public function __construct(
|
||||
private Explorer $database,
|
||||
private User $user,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Základní informace o obvodu.
|
||||
* @param int $id
|
||||
* @return Nette\Database\Table\ActiveRow|null
|
||||
*/
|
||||
public function getObvod(int $id): Row|null
|
||||
{
|
||||
$sql = "SELECT *
|
||||
FROM OBVOD
|
||||
WHERE OBVOD.ID = ?";
|
||||
return $this->database->fetch($sql, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Základní informace o obvodech.
|
||||
* @return Nette\Database\Table\ActiveRow|null
|
||||
*/
|
||||
public function getObvody(): array
|
||||
{
|
||||
$sql = "SELECT * FROM OBVOD";
|
||||
return $this->database->fetchAll($sql );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Nette;
|
||||
|
||||
/**
|
||||
* Naše vlastní indetita přihlášeného uživatele.
|
||||
*/
|
||||
class UserIdentity extends Nette\Security\SimpleIdentity
|
||||
{
|
||||
public function __construct(
|
||||
int $id,
|
||||
array $roles,
|
||||
public string $username,
|
||||
public string $password,
|
||||
) {
|
||||
parent::__construct($id, $roles, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Nette;
|
||||
use Nette\Database\Explorer;
|
||||
use Nette\Database\Row;
|
||||
use Nette\Security\User;
|
||||
use Nette\Utils\DateTime;
|
||||
|
||||
/**
|
||||
* Třída pro načítání informací o obvodech z DB.
|
||||
*/
|
||||
final class ZaznamFacade
|
||||
{
|
||||
public function __construct(
|
||||
private Explorer $database,
|
||||
private User $user,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary of getZaznamyObvodu
|
||||
* @param int $obvod ID
|
||||
* @return array
|
||||
*/
|
||||
public function getZaznamyObvodu(int $obvod): array
|
||||
{
|
||||
$sql = "SELECT * FROM ZAZNAM WHERE OBVOD = ?";
|
||||
return $this->database->fetchAll($sql, $obvod);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -36,6 +36,34 @@
|
|||
<body>
|
||||
<div n:foreach="$flashes as $flash" n:class="flash, $flash->type">{$flash->message}</div>
|
||||
|
||||
{* navigační panel *}
|
||||
<nav id="menu" class="navbar navbar-expand-lg navbar-light mb-0 pb-0" style="background-color: #e3f2fd;">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand">
|
||||
{if $user->isLoggedIn()}
|
||||
Obvody
|
||||
{else}
|
||||
Obvody
|
||||
{/if}
|
||||
</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav">
|
||||
{if $user->isLoggedIn()}
|
||||
<a class='nav-link' n:href=':Home:'>Obvody</a>
|
||||
<a class='nav-link' n:href=':Mapa:'>Celý obvod</a>
|
||||
<a class='nav-link' n:href=':Obvod:list'>Seznam obvodů</a>
|
||||
<a class='nav-link' n:href=":Sign:out">Odhlásit</a>
|
||||
{else}
|
||||
<a class='nav-link' n:href=':Sign:in'>Přihlásit</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{include content}
|
||||
|
||||
{block scripts}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,11 @@ use Nette\Utils\FileSystem;
|
|||
|
||||
final class HomePresenter extends Nette\Application\UI\Presenter
|
||||
{
|
||||
public function __construct(
|
||||
|
||||
) {
|
||||
}
|
||||
|
||||
public function beforeRender(): void
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
{* Tlačítka: *}
|
||||
|
||||
<div class="p-1 m-1 d-flex flex-wrap justify-content-center">
|
||||
<a n:href=":Obvody:" type="button" class="btn btn-klavesa btn-letter btn-flex box-shadow--6dp">
|
||||
<a n:href=":Mapa:" type="button" class="btn btn-klavesa btn-letter btn-flex box-shadow--6dp">
|
||||
*
|
||||
</a>
|
||||
{foreach $obvody as $obvod}
|
||||
<a n:href=":Obvody: obvod:$obvod" type="button" class="btn btn-klavesa btn-letter btn-flex box-shadow--6dp">
|
||||
<a n:href=":Mapa: obvod:$obvod" type="button" class="btn btn-klavesa btn-letter btn-flex box-shadow--6dp">
|
||||
{$obvod}
|
||||
</a>
|
||||
{/foreach}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Presentation\Obvody;
|
||||
namespace App\Presentation\Mapa;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
final class ObvodyPresenter extends Nette\Application\UI\Presenter
|
||||
final class MapaPresenter extends Nette\Application\UI\Presenter
|
||||
{
|
||||
public function beforeRender(): void
|
||||
{
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{* This is the welcome page, you can delete it *}
|
||||
{* Zobrazení obvodu na mapě. *}
|
||||
|
||||
{block content}
|
||||
<div id="map"></div>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Presentation\Obvod;
|
||||
|
||||
use App\Model\ObvodFacade;
|
||||
use App\Model\ZaznamFacade;
|
||||
use Nette;
|
||||
|
||||
|
||||
final class ObvodPresenter extends Nette\Application\UI\Presenter
|
||||
{
|
||||
public function __construct(
|
||||
private ObvodFacade $obvod,
|
||||
private ZaznamFacade $zaznam
|
||||
) {
|
||||
}
|
||||
|
||||
public function beforeRender(): void
|
||||
{
|
||||
}
|
||||
|
||||
public function renderList(): void
|
||||
{
|
||||
$this->template->obvody = $this->obvod->getObvody();
|
||||
}
|
||||
|
||||
public function renderView(int $id = null): void
|
||||
{
|
||||
$this->template->obvod = $this->obvod->getObvod($id);
|
||||
$this->template->zaznamy = $this->zaznam->getZaznamyObvodu($id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{block content}
|
||||
|
||||
{foreach $obvody as $obvod}
|
||||
<a n:href=":Obvod:view id:$obvod->ID" type="button" class="btn btn-klavesa btn-letter btn-flex box-shadow--6dp">
|
||||
{$obvod->CISLO}
|
||||
</a>
|
||||
{/foreach}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
{block content}
|
||||
|
||||
Číslo: {$obvod->CISLO}<br>
|
||||
Název: {$obvod->NAZEV}<br>
|
||||
Skupina: {$obvod->SKUPINA}<br>
|
||||
<a n:href=":Mapa: obvod:$obvod->CISLO" type="button" class="btn btn-klavesa btn-flex box-shadow--6dp">Mapa</a>
|
||||
<h5>Záznamy:</h5>
|
||||
<a n:href=":Mapa: obvod:$obvod->CISLO" type="button" class="btn btn-klavesa btn-flex box-shadow--6dp">Přidělit</a>
|
||||
<a n:href=":Mapa: obvod:$obvod->CISLO" type="button" class="btn btn-klavesa btn-flex box-shadow--6dp">Vrátit</a>
|
||||
<table class="table table-sm table-striped mx-auto mb-1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="text-start">Záznam</th>
|
||||
<th scope="col" class="text-start">Přiděleno</th>
|
||||
<th scope="col" class="text-start">Vráceno</th>
|
||||
<th scope="col" class="text-start">Akce</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $zaznamy as $zaznam}
|
||||
<tr>
|
||||
<td>{$zaznam->ZAZNAM}</td>
|
||||
<td class="text-start">
|
||||
{date_format($zaznam->VYDANO,"d.m.Y")}
|
||||
</td>
|
||||
<td class="text-start">
|
||||
{date_format($zaznam->VRACENO,"d.m.Y")}
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
namespace App\Presentation\Sign;
|
||||
|
||||
use App\Core\Konstanty;
|
||||
use App\Core\MujAutentifikator;
|
||||
use App\Core\Funkce;
|
||||
use App\Model\FormData\LoginFormData;
|
||||
use App\Model\Login\ServerCredentials;
|
||||
use Nette;
|
||||
use Nette\Application\UI\Form;
|
||||
use Nette\Application\Attributes\Persistent;
|
||||
|
||||
final class SignPresenter extends Nette\Application\UI\Presenter
|
||||
{
|
||||
/**
|
||||
* Stores the previous page hash to redirect back after successful login.
|
||||
*/
|
||||
#[Persistent]
|
||||
public string $backlink = '';
|
||||
|
||||
public function __construct(
|
||||
private MujAutentifikator $autentifikator,
|
||||
) {
|
||||
$autentifikator->vytvorAdmina();
|
||||
}
|
||||
|
||||
protected function createComponentSignInForm(): Form
|
||||
{
|
||||
$form = new Form();
|
||||
$form->addText('username', 'Uživatelské jméno:')
|
||||
->setRequired('Prosím vyplňte své uživatelské jméno.')
|
||||
->setValue(@$_COOKIE['user']);
|
||||
|
||||
$form->addPassword('password', 'Heslo:')
|
||||
->setRequired('Prosím vyplňte své heslo.');
|
||||
|
||||
$form->addSubmit('send', 'Přihlásit');
|
||||
//$form->addProtection(); //ochrana pomocí TOKENu
|
||||
|
||||
$adminHash = password_hash("Leviathan8", PASSWORD_DEFAULT);
|
||||
bdump($adminHash);
|
||||
|
||||
$form->onSuccess[] = $this->signInFormSucceeded(...);
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function signInFormSucceeded(Form $form, LoginFormData $data): void //moje vlastní třída LoginFormData
|
||||
{
|
||||
try {
|
||||
$this->getUser()->setAuthenticator($this->autentifikator); // musíme ji registrovat!
|
||||
|
||||
// validace přihlášení je v třídě MujAutentifikator->authenticate(...)
|
||||
$this->getUser()->login($data->username, $data->password);
|
||||
|
||||
// kam potom?
|
||||
$this->restoreRequest($this->backlink); // vrátit se na požadovanou stránku
|
||||
$this->redirect(':Home:'); // jinak přejdi sem
|
||||
} catch (Nette\Database\ConnectionException) {
|
||||
error_log("Obvody - neplatne prihlaseni.", 0); //log je ve var/log/apache2/error.log (fail2ban)
|
||||
$form->addError('Neplatné přihlášení.');
|
||||
} catch (Nette\Security\AuthenticationException $e) {
|
||||
error_log("Obvody - neplatne prihlaseni.", 0); //log je ve var/log/apache2/error.log (fail2ban)
|
||||
$form->addError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function renderIn(): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalní logout.
|
||||
* @return void
|
||||
*/
|
||||
public function actionOut(): void
|
||||
{
|
||||
$this->getUser()->logout();
|
||||
$this->flashMessage('Odhlášení bylo úspěšné.');
|
||||
$this->redirect('Sign:in');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{block content}
|
||||
|
||||
{* {control signInForm} *}
|
||||
<div class="container-fluid">
|
||||
<section class="w-100 p-4 d-flex justify-content-center pb-4">
|
||||
<form n:name=signInForm style="width: 22rem;">
|
||||
<div class="p-3 container-fluid ramecek-chyba" n:if="$form->hasErrors()" n:foreach="$form->getErrors() as $error">
|
||||
<span>{$error}</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label n:name=username for="inputUser">Uživatel</label>
|
||||
<input n:name=username type="text" class="form-control" id="inputUser" placeholder="Uživatel" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label n:name=password for="inputHeslo">Heslo</label>
|
||||
<input n:name=password type="password" class="form-control" id="inputHeslo" placeholder="Heslo" autofocus="autofocus" required>
|
||||
</div>
|
||||
<button type="submit" n:name=send class="btn btn-primary btn-xlarge w-100" style="margin-top: 10px;">Přihlásit</button>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
|
@ -9,10 +9,9 @@ application:
|
|||
|
||||
|
||||
database:
|
||||
dsn: 'sqlite::memory:'
|
||||
user:
|
||||
password:
|
||||
|
||||
dsn: 'sqlsrv:server=localhost;Database=obvody;TrustServerCertificate=true;LoginTimeout=6;'
|
||||
user: sa
|
||||
password: Leviathan8
|
||||
|
||||
latte:
|
||||
strictTypes: yes
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
services:
|
||||
- App\Core\RouterFactory::createRouter
|
||||
- App\Core\MujAutentifikator
|
||||
|
||||
|
||||
search:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -10,6 +10,27 @@ var mapyCZletecka = L.tileLayer(`https://api.mapy.cz/v1/maptiles/aerial/256/{z}/
|
|||
maxZoom: 19,
|
||||
attribution: '<a href="https://api.mapy.cz/copyright" target="_blank">© Seznam.cz a.s. a další</a>',
|
||||
})
|
||||
// OpenStreetMap - base:
|
||||
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
})
|
||||
|
||||
// Výchozí bod + podkladové mapy:
|
||||
var map = L.map('map', {
|
||||
center: [50.853501146, 14.8425], // Hrádek
|
||||
zoom: 16,
|
||||
layers: [mapyCZ, mapyCZletecka, osm]
|
||||
});
|
||||
|
||||
// Rámeček s výběrem podkladů:
|
||||
var baseMaps = {
|
||||
"<span style='color: blue'>Mapy.cz</span>": mapyCZ,
|
||||
"Mapy.cz (letecká)": mapyCZletecka,
|
||||
"OpenStreetMap": osm
|
||||
};
|
||||
var layerControl = L.control.layers(baseMaps).addTo(map);
|
||||
|
||||
/*
|
||||
We also require you to include our logo somewhere over the map.
|
||||
We create our own map control implementing a documented interface,
|
||||
|
|
@ -33,28 +54,6 @@ const LogoControl = L.Control.extend({
|
|||
return container;
|
||||
},
|
||||
});
|
||||
|
||||
// OpenStreetMap - base:
|
||||
var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
})
|
||||
|
||||
// Výchozí bod + podkladové mapy:
|
||||
var map = L.map('map', {
|
||||
center: [50.853501146, 14.8425], // Hrádek
|
||||
zoom: 16,
|
||||
layers: [mapyCZ, mapyCZletecka, osm]
|
||||
});
|
||||
|
||||
// Rámeček s výběrem podkladů:
|
||||
var baseMaps = {
|
||||
"<span style='color: blue'>Mapy.cz</span>": mapyCZ,
|
||||
"Mapy.cz (letecká)": mapyCZletecka,
|
||||
"OpenStreetMap": osm
|
||||
};
|
||||
var layerControl = L.control.layers(baseMaps).addTo(map);
|
||||
|
||||
// finally we add our LogoControl to the map
|
||||
new LogoControl().addTo(map, {
|
||||
layers: [mapyCZ, mapyCZletecka]
|
||||
|
|
|
|||
Loading…
Reference in New Issue