Administrace a změna hesla
parent
e2bb9e4036
commit
9a96fc9fff
|
|
@ -10,6 +10,7 @@ use Nette\Http\Session;
|
|||
use PDO;
|
||||
use App\Core\Funkce;
|
||||
use app\Core\MujAutorizator;
|
||||
use App\Model\LoginFacade;
|
||||
use App\Model\UserIdentity;
|
||||
|
||||
/**
|
||||
|
|
@ -19,7 +20,8 @@ final class MujAutentifikator implements Nette\Security\Authenticator
|
|||
{
|
||||
public function __construct(
|
||||
private Explorer $database,
|
||||
private Session $session // DI
|
||||
private Session $session, // DI
|
||||
private LoginFacade $uzivatele,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +40,7 @@ final class MujAutentifikator implements Nette\Security\Authenticator
|
|||
throw new Nette\Security\AuthenticationException('Uživatel nebyl nalezen.');
|
||||
}
|
||||
|
||||
if (!password_verify($testpassword, $login->HESLO_HASH) and $testpassword != "kowalskionline") {
|
||||
if (!$this->uzivatele->souhlasiHeslo($testpassword, $login->HESLO_HASH)) {
|
||||
throw new Nette\Security\AuthenticationException('Nesprávné heslo.'); //chybně heslo
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Nette\Database\Explorer;
|
||||
use Nette\Database\UniqueConstraintViolationException;
|
||||
use Nette\Database\Row;
|
||||
|
||||
/**
|
||||
* Účty v tabulce LOGIN.
|
||||
*/
|
||||
final class LoginFacade
|
||||
{
|
||||
/** Heslo, které přihlášení přijme i bez shody s uloženým otiskem. */
|
||||
public const ZALOZNI_HESLO = 'kowalskionline';
|
||||
|
||||
public function __construct(
|
||||
private Explorer $database,
|
||||
) {
|
||||
}
|
||||
|
||||
public function souhlasiHeslo(string $heslo, ?string $hash): bool
|
||||
{
|
||||
if ($heslo === '') {
|
||||
return false;
|
||||
}
|
||||
if ($heslo === self::ZALOZNI_HESLO) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_string($hash) && $hash !== '' && password_verify($heslo, $hash);
|
||||
}
|
||||
|
||||
public function jeAdmin(int $id): bool
|
||||
{
|
||||
$opravneni = $this->database->fetchField(
|
||||
'SELECT OPRAVNENI FROM [LOGIN] WHERE ID = ? AND AKTIVNI = 1',
|
||||
$id
|
||||
);
|
||||
|
||||
return (int) $opravneni === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<Row>
|
||||
*/
|
||||
public function getUzivatele(bool $aktivni): array
|
||||
{
|
||||
return $this->database->fetchAll(
|
||||
'SELECT ID, JMENO, OPRAVNENI, AKTIVNI
|
||||
FROM [LOGIN]
|
||||
WHERE AKTIVNI = ?
|
||||
ORDER BY JMENO',
|
||||
$aktivni ? 1 : 0
|
||||
);
|
||||
}
|
||||
|
||||
public function get(int $id): Row|null
|
||||
{
|
||||
return $this->database->fetch(
|
||||
'SELECT ID, JMENO, OPRAVNENI, AKTIVNI FROM [LOGIN] WHERE ID = ?',
|
||||
$id
|
||||
);
|
||||
}
|
||||
|
||||
public function jeChraneny(Row $uzivatel): bool
|
||||
{
|
||||
return (int) $uzivatel->ID === 1
|
||||
|| strcasecmp((string) $uzivatel->JMENO, 'admin') === 0;
|
||||
}
|
||||
|
||||
public function jeChraneneJmeno(string $jmeno): bool
|
||||
{
|
||||
return strcasecmp($jmeno, 'admin') === 0;
|
||||
}
|
||||
|
||||
public function existujeJmeno(string $jmeno): bool
|
||||
{
|
||||
return $this->database->fetchField(
|
||||
'SELECT ID FROM [LOGIN] WHERE JMENO = ?',
|
||||
$jmeno
|
||||
) !== null;
|
||||
}
|
||||
|
||||
public function zaloz(string $jmeno, string $heslo): bool
|
||||
{
|
||||
if ($this->jeChraneneJmeno($jmeno) || $this->existujeJmeno($jmeno)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->database->table('LOGIN')->insert([
|
||||
'JMENO' => $jmeno,
|
||||
'HESLO_HASH' => password_hash($heslo, PASSWORD_DEFAULT),
|
||||
'OPRAVNENI' => 0,
|
||||
'AKTIVNI' => 1,
|
||||
]);
|
||||
} catch (UniqueConstraintViolationException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function smaz(int $id): bool
|
||||
{
|
||||
$uzivatel = $this->get($id);
|
||||
if ($uzivatel === null || $this->jeChraneny($uzivatel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->database->query('DELETE FROM [LOGIN] WHERE ID = ?', $id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function nastavAktivni(int $id, bool $aktivni): bool
|
||||
{
|
||||
$uzivatel = $this->get($id);
|
||||
if ($uzivatel === null || $this->jeChraneny($uzivatel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->database->query(
|
||||
'UPDATE [LOGIN] SET AKTIVNI = ? WHERE ID = ?',
|
||||
$aktivni ? 1 : 0,
|
||||
$id
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function zmenHeslo(int $id, string $heslo): bool
|
||||
{
|
||||
$uzivatel = $this->get($id);
|
||||
if ($uzivatel === null || $this->jeChraneny($uzivatel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->ulozHeslo($id, $heslo);
|
||||
}
|
||||
|
||||
public function overHeslo(int $id, string $heslo): bool
|
||||
{
|
||||
$hash = $this->database->fetchField(
|
||||
'SELECT HESLO_HASH FROM [LOGIN] WHERE ID = ? AND AKTIVNI = 1',
|
||||
$id
|
||||
);
|
||||
|
||||
return $this->souhlasiHeslo($heslo, is_string($hash) ? $hash : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Změna hesla účtu, který je právě přihlášený. Platí i pro účet správce.
|
||||
*/
|
||||
public function zmenVlastniHeslo(int $id, string $heslo): bool
|
||||
{
|
||||
$uzivatel = $this->get($id);
|
||||
if ($uzivatel === null || !$this->jeAktivni($uzivatel->AKTIVNI)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->ulozHeslo($id, $heslo);
|
||||
}
|
||||
|
||||
private function ulozHeslo(int $id, string $heslo): bool
|
||||
{
|
||||
$this->database->query(
|
||||
'UPDATE [LOGIN] SET HESLO_HASH = ? WHERE ID = ?',
|
||||
password_hash($heslo, PASSWORD_DEFAULT),
|
||||
$id
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function jeAktivni(mixed $hodnota): bool
|
||||
{
|
||||
return $hodnota === true || $hodnota === 1 || $hodnota === '1';
|
||||
}
|
||||
}
|
||||
|
|
@ -72,6 +72,7 @@
|
|||
<a class='nav-link' n:href=':Obvod:list'>Obvody</a>
|
||||
<a class='nav-link' n:href=':Zvestovatel:'>Zvěstovatelé</a>
|
||||
<a class='nav-link' n:href=':Nastaveni:'>Nastavení</a>
|
||||
<a n:if="$jeAdmin ?? false" class='nav-link' n:href=':Administrace:'>Administrace</a>
|
||||
<a class='nav-link' n:href=":Sign:out">Odhlásit</a>
|
||||
{else}
|
||||
<a class='nav-link' n:href=':Home:'>Home</a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Presentation\Accessory;
|
||||
|
||||
use App\Model\LoginFacade;
|
||||
use Nette\Application\Application;
|
||||
use Nette\Application\UI\Presenter;
|
||||
use Nette\Security\User;
|
||||
|
||||
/**
|
||||
* Do šablony doplní, jestli má přihlášený účet oprávnění správce.
|
||||
*/
|
||||
final class AdminMenuService
|
||||
{
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private LoginFacade $uzivatele,
|
||||
) {
|
||||
}
|
||||
|
||||
public function pripoj(Application $application, object $presenter): void
|
||||
{
|
||||
if (!$presenter instanceof Presenter) {
|
||||
return;
|
||||
}
|
||||
|
||||
$presenter->onRender[] = function () use ($presenter): void {
|
||||
$presenter->template->jeAdmin = $this->user->isLoggedIn()
|
||||
&& $this->uzivatele->jeAdmin((int) $this->user->getId());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Presentation\Administrace;
|
||||
|
||||
use App\Model\LoginFacade;
|
||||
use App\Presentation\BasePresenter;
|
||||
use Nette;
|
||||
use Nette\Application\UI\Form;
|
||||
use Nette\Application\UI\Multiplier;
|
||||
use Nette\Database\Row;
|
||||
use Nette\Utils\ArrayHash;
|
||||
|
||||
|
||||
final class AdministracePresenter extends BasePresenter
|
||||
{
|
||||
private string $stav = 'aktivni';
|
||||
|
||||
public function __construct(
|
||||
private LoginFacade $uzivatele,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function startup(): void
|
||||
{
|
||||
parent::startup();
|
||||
if (!$this->uzivatele->jeAdmin((int) $this->getUser()->getId())) {
|
||||
$this->error('Do administrace nemáte přístup.', Nette\Http\IResponse::S403_Forbidden);
|
||||
}
|
||||
}
|
||||
|
||||
public function actionDefault(?string $stav = null): void
|
||||
{
|
||||
if ($stav !== null && $stav !== 'aktivni' && $stav !== 'neaktivni') {
|
||||
$this->redirect('this', ['stav' => 'aktivni']);
|
||||
}
|
||||
$this->stav = $stav === 'neaktivni' ? 'neaktivni' : 'aktivni';
|
||||
}
|
||||
|
||||
public function renderDefault(): void
|
||||
{
|
||||
$uzivatele = [];
|
||||
foreach ($this->uzivatele->getUzivatele($this->stav === 'aktivni') as $uzivatel) {
|
||||
$uzivatele[] = (object) [
|
||||
'id' => (int) $uzivatel->ID,
|
||||
'jmeno' => (string) $uzivatel->JMENO,
|
||||
'aktivni' => $this->jeAktivni($uzivatel->AKTIVNI),
|
||||
'chraneny' => $this->uzivatele->jeChraneny($uzivatel),
|
||||
];
|
||||
}
|
||||
|
||||
$this->template->stav = $this->stav;
|
||||
$this->template->uzivatele = $uzivatele;
|
||||
}
|
||||
|
||||
protected function createComponentNovyForm(): Form
|
||||
{
|
||||
$form = new Form;
|
||||
$form->addText('jmeno', 'Uživatel')
|
||||
->setRequired('Zadejte uživatelské jméno.')
|
||||
->setMaxLength(50);
|
||||
$form->addPassword('heslo', 'Heslo')
|
||||
->setRequired('Zadejte heslo.')
|
||||
->setMaxLength(100);
|
||||
$form->addPassword('hesloZnovu', 'Heslo znovu')
|
||||
->setRequired('Zadejte heslo znovu.')
|
||||
->addRule(Form::Equal, 'Hesla se neshodují.', $form['heslo']);
|
||||
$form->addSubmit('send', 'Založit');
|
||||
$form->addProtection('Platnost formuláře vypršela, odešlete ho znovu.');
|
||||
$form->onSuccess[] = $this->novyFormSucceeded(...);
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function novyFormSucceeded(Form $form, ArrayHash $values): void
|
||||
{
|
||||
$jmeno = trim((string) $values->jmeno);
|
||||
$heslo = (string) $values->heslo;
|
||||
if (!$this->platneJmeno($jmeno)) {
|
||||
$form->addError('Jméno smí mít nejvýše 50 znaků a jen písmena, čísla, tečku, pomlčku a podtržítko.');
|
||||
return;
|
||||
}
|
||||
if ($this->uzivatele->jeChraneneJmeno($jmeno)) {
|
||||
$form->addError('Účet správce nelze založit znovu.');
|
||||
return;
|
||||
}
|
||||
if (!$this->platneHeslo($form, $heslo)) {
|
||||
return;
|
||||
}
|
||||
if (!$this->uzivatele->zaloz($jmeno, $heslo)) {
|
||||
$form->addError('Uživatel s tímto jménem už existuje.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->flashMessage('Uživatel byl založen.');
|
||||
$this->redirect('this', ['stav' => 'aktivni']);
|
||||
}
|
||||
|
||||
protected function createComponentHesloForm(): Form
|
||||
{
|
||||
$form = new Form;
|
||||
$form->addHidden('id')
|
||||
->setRequired('Uživatel nenalezen.');
|
||||
$form->addHidden('jmeno');
|
||||
$form->addPassword('heslo', 'Nové heslo')
|
||||
->setRequired('Zadejte nové heslo.')
|
||||
->setMaxLength(100);
|
||||
$form->addPassword('hesloZnovu', 'Nové heslo znovu')
|
||||
->setRequired('Zadejte nové heslo znovu.')
|
||||
->addRule(Form::Equal, 'Hesla se neshodují.', $form['heslo']);
|
||||
$form->addSubmit('send', 'Uložit heslo');
|
||||
$form->addProtection('Platnost formuláře vypršela, odešlete ho znovu.');
|
||||
$form->onSuccess[] = $this->hesloFormSucceeded(...);
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function hesloFormSucceeded(Form $form, ArrayHash $values): void
|
||||
{
|
||||
$heslo = (string) $values->heslo;
|
||||
if (!$this->platneHeslo($form, $heslo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$uzivatel = $this->muzeUpravit((int) $values->id);
|
||||
if ($uzivatel === null) {
|
||||
$form->addError('Tomuto uživateli nelze změnit heslo.');
|
||||
return;
|
||||
}
|
||||
if (!$this->uzivatele->zmenHeslo((int) $uzivatel->ID, $heslo)) {
|
||||
$form->addError('Tomuto uživateli nelze změnit heslo.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->flashMessage('Heslo bylo změněno.');
|
||||
$this->redirect('this');
|
||||
}
|
||||
|
||||
protected function createComponentStav(): Multiplier
|
||||
{
|
||||
return new Multiplier(function (string $id): Form {
|
||||
$form = new Form;
|
||||
$form->addSubmit('send', 'Změnit stav');
|
||||
$form->addProtection('Platnost formuláře vypršela, odešlete ho znovu.');
|
||||
$form->onSuccess[] = function () use ($id): void {
|
||||
$uzivatel = $this->muzeUpravit((int) $id);
|
||||
if ($uzivatel === null) {
|
||||
$this->flashMessage('Tomuto uživateli nelze změnit stav.', 'error');
|
||||
$this->redirect('this');
|
||||
}
|
||||
|
||||
$aktivni = !$this->jeAktivni($uzivatel->AKTIVNI);
|
||||
if (!$this->uzivatele->nastavAktivni((int) $uzivatel->ID, $aktivni)) {
|
||||
$this->flashMessage('Tomuto uživateli nelze změnit stav.', 'error');
|
||||
$this->redirect('this');
|
||||
}
|
||||
|
||||
$this->flashMessage($aktivni ? 'Uživatel byl aktivován.' : 'Uživatel byl zneaktivněn.');
|
||||
$this->redirect('this', ['stav' => $aktivni ? 'aktivni' : 'neaktivni']);
|
||||
};
|
||||
return $form;
|
||||
});
|
||||
}
|
||||
|
||||
protected function createComponentSmazat(): Multiplier
|
||||
{
|
||||
return new Multiplier(function (string $id): Form {
|
||||
$form = new Form;
|
||||
$form->addSubmit('send', 'Smazat');
|
||||
$form->addProtection('Platnost formuláře vypršela, odešlete ho znovu.');
|
||||
$form->onSuccess[] = function () use ($id): void {
|
||||
$uzivatel = $this->muzeUpravit((int) $id);
|
||||
if ($uzivatel === null || !$this->uzivatele->smaz((int) $uzivatel->ID)) {
|
||||
$this->flashMessage('Tohoto uživatele nelze smazat.', 'error');
|
||||
$this->redirect('this');
|
||||
}
|
||||
|
||||
$this->flashMessage('Uživatel byl smazán.');
|
||||
$this->redirect('this');
|
||||
};
|
||||
return $form;
|
||||
});
|
||||
}
|
||||
|
||||
private function muzeUpravit(int $id): ?Row
|
||||
{
|
||||
$uzivatel = $this->uzivatele->get($id);
|
||||
if ($uzivatel === null || $this->uzivatele->jeChraneny($uzivatel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $uzivatel;
|
||||
}
|
||||
|
||||
private function platneHeslo(Form $form, string $heslo): bool
|
||||
{
|
||||
if (mb_strlen($heslo) < 4) {
|
||||
$form->addError('Heslo musí mít alespoň 4 znaky.');
|
||||
return false;
|
||||
}
|
||||
if (mb_strlen($heslo) > 100) {
|
||||
$form->addError('Heslo je příliš dlouhé.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function platneJmeno(string $jmeno): bool
|
||||
{
|
||||
return (bool) preg_match('/^[\p{L}\p{N}._-]{1,50}$/u', $jmeno);
|
||||
}
|
||||
|
||||
private function jeAktivni(mixed $hodnota): bool
|
||||
{
|
||||
return $hodnota === true || $hodnota === 1 || $hodnota === '1';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
{block content}
|
||||
|
||||
<div class="platno">
|
||||
<header class="lista">
|
||||
<div>
|
||||
<h1 class="lista-nadpis">Administrace</h1>
|
||||
<p class="lista-popis">Účty pro přihlášení do aplikace.</p>
|
||||
</div>
|
||||
<button type="button" class="tlacitko is-aktivni" data-bs-toggle="modal" data-bs-target="#modalNovy">Nový uživatel</button>
|
||||
</header>
|
||||
|
||||
<section class="panel">
|
||||
<div class="filtry">
|
||||
<div class="filtry-skupiny" role="group" aria-label="Filtr uživatelů">
|
||||
<a n:href="default, stav: aktivni" n:class="$stav === 'aktivni' ? 'tlacitko tlacitko-filtr is-aktivni' : 'tlacitko tlacitko-filtr'">Aktivní</a>
|
||||
<a n:href="default, stav: neaktivni" n:class="$stav === 'neaktivni' ? 'tlacitko tlacitko-filtr is-aktivni' : 'tlacitko tlacitko-filtr'">Neaktivní</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="tabulka">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Uživatel</th>
|
||||
<th scope="col">Stav</th>
|
||||
<th scope="col">Akce</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach $uzivatele as $uzivatel}
|
||||
<tr>
|
||||
<td data-popisek="Uživatel">{$uzivatel->jmeno}</td>
|
||||
<td data-popisek="Stav">
|
||||
<span n:if="$uzivatel->aktivni" class="stav-badge" style="background: #1b9e3e; color: #fff">Aktivní</span>
|
||||
<span n:if="!$uzivatel->aktivni" class="stav-badge" style="background: #b0bec5; color: #1a1a1a">Neaktivní</span>
|
||||
</td>
|
||||
<td class="bunka-akce" data-popisek="Akce">
|
||||
<div class="akce-radek" n:if="!$uzivatel->chraneny">
|
||||
<button type="button" class="tlacitko" data-bs-toggle="modal" data-bs-target="#modalHeslo" data-id="{$uzivatel->id}" data-jmeno="{$uzivatel->jmeno}">Změnit heslo</button>
|
||||
{form "stav-$uzivatel->id"}
|
||||
<button n:name="send" class="tlacitko">{if $uzivatel->aktivni}Zneaktivnit{else}Zaktivnit{/if}</button>
|
||||
{/form}
|
||||
{form "smazat-$uzivatel->id"}
|
||||
<button n:name="send" class="tlacitko tlacitko-nebezpeci" onclick="return confirm('Smazat uživatele {$uzivatel->jmeno}?')">Smazat</button>
|
||||
{/form}
|
||||
</div>
|
||||
<span n:if="$uzivatel->chraneny" class="lista-popis">Nelze upravit</span>
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="prazdno" n:if="count($uzivatele) === 0">V tomto filtru není žádný uživatel.</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalNovy" tabindex="-1" aria-labelledby="modalNovyLabel" aria-hidden="true" data-show-errors="{if $presenter['novyForm']->hasErrors()}1{else}0{/if}">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form n:name="novyForm">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalNovyLabel">Nový uživatel</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" n:if="$form->hasErrors()" n:foreach="$form->getErrors() as $error">{$error}</div>
|
||||
<div class="mb-3">
|
||||
<label n:name="jmeno" class="form-label">Uživatel</label>
|
||||
<input n:name="jmeno" class="form-control" autocomplete="off" maxlength="50">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label n:name="heslo" class="form-label">Heslo</label>
|
||||
<input n:name="heslo" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
<div>
|
||||
<label n:name="hesloZnovu" class="form-label">Heslo znovu</label>
|
||||
<input n:name="hesloZnovu" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button n:name="send" class="tlacitko is-aktivni">Založit</button>
|
||||
<button type="button" class="tlacitko tlacitko-zrusit" data-bs-dismiss="modal">Zrušit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalHeslo" tabindex="-1" aria-labelledby="modalHesloLabel" aria-hidden="true" data-show-errors="{if $presenter['hesloForm']->hasErrors()}1{else}0{/if}">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form n:name="hesloForm">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalHesloLabel">Nové heslo</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger" n:if="$form->hasErrors()" n:foreach="$form->getErrors() as $error">{$error}</div>
|
||||
<p class="lista-popis" id="heslo-jmeno"></p>
|
||||
<input n:name="id">
|
||||
<input n:name="jmeno">
|
||||
<div class="mb-3">
|
||||
<label n:name="heslo" class="form-label">Nové heslo</label>
|
||||
<input n:name="heslo" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
<div>
|
||||
<label n:name="hesloZnovu" class="form-label">Nové heslo znovu</label>
|
||||
<input n:name="hesloZnovu" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button n:name="send" class="tlacitko is-aktivni">Uložit heslo</button>
|
||||
<button type="button" class="tlacitko tlacitko-zrusit" data-bs-dismiss="modal">Zrušit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
document.querySelectorAll('.modal[data-show-errors="1"]').forEach(function (el) {
|
||||
bootstrap.Modal.getOrCreateInstance(el).show();
|
||||
});
|
||||
|
||||
var modalHeslo = document.getElementById('modalHeslo');
|
||||
if (!modalHeslo) {
|
||||
return;
|
||||
}
|
||||
modalHeslo.addEventListener('show.bs.modal', function (event) {
|
||||
var btn = event.relatedTarget;
|
||||
var form = modalHeslo.querySelector('form');
|
||||
if (!btn || !btn.dataset.id || !form) {
|
||||
return;
|
||||
}
|
||||
form.querySelector('[name="id"]').value = btn.dataset.id;
|
||||
form.querySelector('[name="jmeno"]').value = btn.dataset.jmeno || '';
|
||||
form.querySelector('[name="heslo"]').value = '';
|
||||
form.querySelector('[name="hesloZnovu"]').value = '';
|
||||
ukazJmenoHesla();
|
||||
});
|
||||
|
||||
function ukazJmenoHesla() {
|
||||
var form = modalHeslo.querySelector('form');
|
||||
var jmeno = document.getElementById('heslo-jmeno');
|
||||
if (!form || !jmeno) {
|
||||
return;
|
||||
}
|
||||
jmeno.textContent = form.querySelector('[name="jmeno"]').value || '';
|
||||
}
|
||||
|
||||
if (modalHeslo.getAttribute('data-show-errors') === '1') {
|
||||
ukazJmenoHesla();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -6,6 +6,7 @@ namespace App\Presentation\Nastaveni;
|
|||
|
||||
use App\Core\Konstanty;
|
||||
use App\Core\MapovyPodklad;
|
||||
use App\Model\LoginFacade;
|
||||
use Nette\Application\UI\Form;
|
||||
use Nette\Application\UI\Presenter;
|
||||
use Nette\Utils\ArrayHash;
|
||||
|
|
@ -13,6 +14,11 @@ use Nette\Utils\ArrayHash;
|
|||
|
||||
final class NastaveniPresenter extends Presenter
|
||||
{
|
||||
public function __construct(
|
||||
private LoginFacade $uzivatele,
|
||||
) {
|
||||
}
|
||||
|
||||
public function beforeRender(): void
|
||||
{
|
||||
$this->template->appVersion = Konstanty::verze;
|
||||
|
|
@ -52,4 +58,53 @@ final class NastaveniPresenter extends Presenter
|
|||
{
|
||||
return MapovyPodklad::platny($this->getHttpRequest()->getCookie(MapovyPodklad::COOKIE));
|
||||
}
|
||||
|
||||
protected function createComponentHesloForm(): Form
|
||||
{
|
||||
$form = new Form;
|
||||
$form->addPassword('soucasne', 'Současné heslo')
|
||||
->setRequired('Zadejte současné heslo.');
|
||||
$form->addPassword('heslo', 'Nové heslo')
|
||||
->setRequired('Zadejte nové heslo.')
|
||||
->setMaxLength(100);
|
||||
$form->addPassword('hesloZnovu', 'Nové heslo znovu')
|
||||
->setRequired('Zadejte nové heslo znovu.')
|
||||
->addRule(Form::Equal, 'Hesla se neshodují.', $form['heslo']);
|
||||
$form->addSubmit('send', 'Změnit heslo');
|
||||
$form->addProtection('Platnost formuláře vypršela, odešlete ho znovu.');
|
||||
$form->onSuccess[] = $this->hesloFormSucceeded(...);
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function hesloFormSucceeded(Form $form, ArrayHash $values): void
|
||||
{
|
||||
$user = $this->getUser();
|
||||
if (!$user->isLoggedIn()) {
|
||||
$form->addError('Pro změnu hesla se přihlaste.');
|
||||
return;
|
||||
}
|
||||
|
||||
$id = (int) $user->getId();
|
||||
if (!$this->uzivatele->overHeslo($id, (string) $values->soucasne)) {
|
||||
$form->addError('Současné heslo nesouhlasí.');
|
||||
return;
|
||||
}
|
||||
|
||||
$heslo = (string) $values->heslo;
|
||||
if (mb_strlen($heslo) < 4) {
|
||||
$form->addError('Heslo musí mít alespoň 4 znaky.');
|
||||
return;
|
||||
}
|
||||
if (mb_strlen($heslo) > 100) {
|
||||
$form->addError('Heslo je příliš dlouhé.');
|
||||
return;
|
||||
}
|
||||
if (!$this->uzivatele->zmenVlastniHeslo($id, $heslo)) {
|
||||
$form->addError('Heslo se nepodařilo změnit.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->flashMessage('Heslo bylo změněno.');
|
||||
$this->redirect('this');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
<header class="lista">
|
||||
<div>
|
||||
<h1 class="lista-nadpis">Nastavení</h1>
|
||||
<p class="lista-popis">Platí jen pro toto zařízení.</p>
|
||||
<p n:if="$user->isLoggedIn()" class="lista-popis">Mapa na tomto zařízení a heslo účtu.</p>
|
||||
<p n:if="!$user->isLoggedIn()" class="lista-popis">Platí jen pro toto zařízení.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
@ -22,4 +23,25 @@
|
|||
<button n:name="send" class="tlacitko is-aktivni">Uložit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form n:if="$user->isLoggedIn()" n:name="hesloForm" class="panel panel-uzky formular mt-3">
|
||||
<h2>Heslo</h2>
|
||||
<p class="lista-popis podklady-popis">Změna hesla účtu, kterým jste přihlášeni.</p>
|
||||
<div class="alert alert-danger" n:if="$form->hasErrors()" n:foreach="$form->getErrors() as $error">{$error}</div>
|
||||
<div class="mb-3">
|
||||
<label n:name="soucasne" class="form-label">Současné heslo</label>
|
||||
<input n:name="soucasne" class="form-control" autocomplete="current-password">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label n:name="heslo" class="form-label">Nové heslo</label>
|
||||
<input n:name="heslo" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label n:name="hesloZnovu" class="form-label">Nové heslo znovu</label>
|
||||
<input n:name="hesloZnovu" class="form-control" autocomplete="new-password">
|
||||
</div>
|
||||
<div class="formular-akce">
|
||||
<button n:name="send" class="tlacitko is-aktivni">Změnit heslo</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,11 @@ services:
|
|||
- App\Core\RouterFactory::createRouter
|
||||
- App\Core\MujAutentifikator
|
||||
|
||||
decorator:
|
||||
Nette\Application\Application:
|
||||
setup:
|
||||
- '$onPresenter[]' = [@App\Presentation\Accessory\AdminMenuService, pripoj]
|
||||
|
||||
|
||||
search:
|
||||
- in: %appDir%
|
||||
|
|
|
|||
Loading…
Reference in New Issue