SPRA-2 add admin; add user list; add user; change permissions
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
import $ from 'jquery';
|
||||
|
||||
export default class extends Controller {
|
||||
mainObj
|
||||
deleteButtons
|
||||
confirmModalObj
|
||||
confirmModalUsernameObj
|
||||
connect() {
|
||||
this.mainObj = $(".page.admin.users");
|
||||
this.deleteButtons = this.mainObj.find(".confirmRemoveUser");
|
||||
this.confirmModalObj = this.mainObj.find("#removeConfirmModal");
|
||||
this.confirmModalUsernameObj = this.confirmModalObj.find(".insertUsername");
|
||||
this.bindOnClick()
|
||||
}
|
||||
|
||||
bindOnClick() {
|
||||
this.deleteButtons.on("click", (e) => {
|
||||
const obj = $(e.currentTarget),
|
||||
username = $(obj).attr("data-username"),
|
||||
formLink = $(obj).attr("data-formlink");
|
||||
|
||||
this.confirmModalUsernameObj.html(username);
|
||||
this.confirmModalObj.find("form").attr("action", formLink);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ security:
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
access_control:
|
||||
- { path: ^/login, roles: PUBLIC_ACCESS }
|
||||
- { path: ^/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/, roles: ROLE_USER }
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
|
||||
when@test:
|
||||
security:
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240729204423 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE user ADD activation_hash VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE user DROP activation_hash');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240730092145 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE user ADD date_activation_hash DATETIME DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE user DROP date_activation_hash');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class BaseAdminController extends AbstractController
|
||||
{
|
||||
#[Route('/admin', name: 'app_admin')]
|
||||
public function indexAction(): Response
|
||||
{
|
||||
return $this->render('admin/index.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
use App\Entity\User;
|
||||
use App\Enum\UserPermission;
|
||||
use App\Helper\HashGenerator;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
class UsersController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Expire in hours
|
||||
*/
|
||||
private const _ACTIVATION_HASH_EXPIRE = 6;
|
||||
#[Route('/admin/users', name: 'app_admin_users')]
|
||||
public function indexAction(EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$allUsers = $entityManager->getRepository(User::class)->findAll();
|
||||
|
||||
return $this->render('admin/users/list.html.twig', [
|
||||
'users' => $allUsers,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/users/edit/{id}', name: 'app_admin_user_edit')]
|
||||
public function editPermission(EntityManagerInterface $entityManager, User $user, Request $request): Response
|
||||
{
|
||||
if ($request->getMethod() === 'POST' &&
|
||||
$this->isCsrfTokenValid('admin-user-edit-permission', $request->get('token'))) {
|
||||
foreach (UserPermission::cases() as $case) {
|
||||
if ($case->value === "ROLE_ADMIN") {
|
||||
continue;
|
||||
}
|
||||
$isPermission = false;
|
||||
if ($request->get($case->value)) {
|
||||
$isPermission = true;
|
||||
}
|
||||
|
||||
if ($isPermission) {
|
||||
$user->addRoles($case->value);
|
||||
} else {
|
||||
$user->removeRoles($case->value);
|
||||
}
|
||||
}
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
return $this->render('admin/users/edit.html.twig', [
|
||||
'user' => $user,
|
||||
'permissionAll' => UserPermission::casesGroup()
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/users/add', name: 'app_admin_user_add')]
|
||||
public function addUser(Request $request, EntityManagerInterface $entityManager, UserPasswordHasherInterface $hasher) : Response
|
||||
{
|
||||
$user = new User();
|
||||
$form = $this->createFormBuilder($user)
|
||||
->add('username',TextType::class, ['label'=>'Nazwa użytkownika'])
|
||||
->add('submit',SubmitType::class)
|
||||
->getForm();
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
/** @var User $newUser */
|
||||
$newUser = $form->getData();
|
||||
$hash = $hasher->hashPassword($newUser, HashGenerator::generateHash(32));
|
||||
$newUser->setPassword($hash);
|
||||
$entityManager->persist($newUser);
|
||||
$entityManager->flush();
|
||||
|
||||
return $this->redirectToRoute('app_admin_user_add_success',['id'=>$newUser->getId()]);
|
||||
}
|
||||
|
||||
return $this->render('admin/users/add.html.twig',[
|
||||
'form' => $form->createView(),
|
||||
'plainPassword' => null
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/users/add/{id}', name: 'app_admin_user_add_success')]
|
||||
public function addUserSuccess(User $user, EntityManagerInterface $entityManager) : Response
|
||||
{
|
||||
$newUser = false;
|
||||
if (!$user->getActivationHash() || $user->getDateActivationHash() < new \DateTime()) {
|
||||
$user->setActivationHash(HashGenerator::generateHash(64));
|
||||
$user->setDateActivationHash(new \DateTime("+ ".self::_ACTIVATION_HASH_EXPIRE." hours"));
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
$newUser = true;
|
||||
}
|
||||
|
||||
return $this->render('admin/users/userAddSuccess.html.twig', [
|
||||
'user' => $user,
|
||||
'activationLink' => $this->generateUrl('app_user_activate', ['id'=>$user->getId(),'hash'=>$user->getActivationHash()], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
'newUser' => $newUser
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/admin/users/delete/{id}', name: 'app_admin_user_remove', methods: ['POST'])]
|
||||
public function deleteUser(User $user, EntityManagerInterface $entityManager, Request $request) : Response
|
||||
{
|
||||
if ($this->isCsrfTokenValid('admin-remove-user',$request->get('token'))){
|
||||
$entityManager->remove($user);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_admin_users');
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,18 @@
|
||||
|
||||
namespace App\Controller\User;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Helper\HashGenerator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGenerator;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||
use function Symfony\Component\String\u;
|
||||
|
||||
class SecurityController extends AbstractController
|
||||
{
|
||||
@@ -35,4 +41,27 @@ class SecurityController extends AbstractController
|
||||
{
|
||||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||
}
|
||||
|
||||
#[Route(path: '/user/activate/{id}/{hash}', name: 'app_user_activate')]
|
||||
public function activate(User $user, string $hash, EntityManagerInterface $entityManager, UserPasswordHasherInterface $hasher) : Response
|
||||
{
|
||||
$dateNow = new \DateTime();
|
||||
if ($user->getActivationHash() !== $hash || $user->getDateActivationHash() < $dateNow) {
|
||||
return $this->render('security/passwordGenerate.html.twig', [
|
||||
'user' => null,
|
||||
]);
|
||||
}
|
||||
$newPassword = HashGenerator::generateHash(12);
|
||||
$user->setPassword($hasher->hashPassword($user, $newPassword));
|
||||
$user->setActivationHash(null);
|
||||
$user->setDateActivationHash(null);
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
return $this->render('security/passwordGenerate.html.twig', [
|
||||
'user' => $user,
|
||||
'newPassword' => $newPassword,
|
||||
]);
|
||||
// return new Response("Twój login: `{$user->getUsername()}`. Twoje hasło: `{$newPassword}`");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Enum\UserPermission;
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
@@ -31,6 +33,12 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\Column]
|
||||
private ?string $password = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $activationHash = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||
private ?\DateTimeInterface $dateActivationHash = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -82,6 +90,33 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addRoles(string $role): void
|
||||
{
|
||||
if ($role === 'ROLE_USER') {
|
||||
return;
|
||||
}
|
||||
$roles = $this->getRoles();
|
||||
$roles[] = $role;
|
||||
|
||||
$this->roles = $roles;
|
||||
}
|
||||
|
||||
public function removeRoles(string $roleRemove): void
|
||||
{
|
||||
if ($roleRemove === 'ROLE_USER') {
|
||||
return;
|
||||
}
|
||||
$roles = $this->getRoles();
|
||||
foreach ($roles as $key => $role) {
|
||||
if ($role === $roleRemove) {
|
||||
unset($roles[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$roles = array_values($roles);
|
||||
$this->setRoles($roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PasswordAuthenticatedUserInterface
|
||||
*/
|
||||
@@ -105,4 +140,42 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
|
||||
public function getEnumRoles(): array
|
||||
{
|
||||
$tmp=[];
|
||||
foreach ($this->getRoles() as $role) {
|
||||
$tmp[]=UserPermission::from($role);
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public function isGranted(UserPermission $permission): bool
|
||||
{
|
||||
return in_array($permission, $this->getEnumRoles(), true);
|
||||
}
|
||||
|
||||
public function getActivationHash(): ?string
|
||||
{
|
||||
return $this->activationHash;
|
||||
}
|
||||
|
||||
public function setActivationHash(?string $activationHash): static
|
||||
{
|
||||
$this->activationHash = $activationHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateActivationHash(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->dateActivationHash;
|
||||
}
|
||||
|
||||
public function setDateActivationHash(?\DateTimeInterface $dateActivationHash): static
|
||||
{
|
||||
$this->dateActivationHash = $dateActivationHash;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace App\Enum;
|
||||
|
||||
enum UserPermission : string
|
||||
{
|
||||
case ADMIN = 'ROLE_ADMIN';
|
||||
case USER = 'ROLE_USER';
|
||||
case ALL = 'ROLE_ACCESS_ALL';
|
||||
case CLIENT_ADD = 'ROLE_CLIENT_ADD';
|
||||
case CLIENT_VIEW = 'ROLE_CLIENT_VIEW';
|
||||
case CLIENT_DELETE = 'ROLE_CLIENT_DELETE';
|
||||
case REPORT_VIEW = 'ROLE_REPORT_VIEW';
|
||||
case REPORT_EDIT = 'ROLE_REPORT_EDIT';
|
||||
|
||||
public function takeLang(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::ADMIN => 'Admin',
|
||||
self::USER => 'Zalogowany',
|
||||
self::ALL => 'Pełny dostęp',
|
||||
self::CLIENT_ADD => 'Dodawanie klienta',
|
||||
self::CLIENT_VIEW => 'Wyświetlanie klienta',
|
||||
self::CLIENT_DELETE => 'Usuwanie klientów',
|
||||
self::REPORT_VIEW => 'Wyświetlanie sprawozdań',
|
||||
self::REPORT_EDIT => 'Edycja sprawozdań',
|
||||
};
|
||||
}
|
||||
|
||||
public static function casesGroup() : array
|
||||
{
|
||||
return [
|
||||
'case' => UserPermission::ADMIN,
|
||||
'children' => [
|
||||
[
|
||||
'case' => UserPermission::ALL,
|
||||
'children' => [
|
||||
UserPermission::CLIENT_ADD,
|
||||
UserPermission::CLIENT_VIEW,
|
||||
UserPermission::CLIENT_DELETE,
|
||||
UserPermission::REPORT_VIEW,
|
||||
UserPermission::REPORT_EDIT,
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace App\Helper;
|
||||
|
||||
class HashGenerator
|
||||
{
|
||||
public static function generateHash(int $length): string
|
||||
{
|
||||
$bytes = openssl_random_pseudo_bytes($length);
|
||||
return substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $length);
|
||||
}
|
||||
}
|
||||
@@ -73,4 +73,3 @@ class ClientsVoter extends Voter
|
||||
return $this->security->isGranted('ROLE_ACCESS_ALL');
|
||||
}
|
||||
}
|
||||
//HqmN6Egol5o_K5nY
|
||||
@@ -0,0 +1,18 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% block title %}Admin{% endblock %}
|
||||
{% block body %}
|
||||
<div class="row">
|
||||
<div class="col col-2 card">
|
||||
<div class="card-body d-flex justify-content-center">
|
||||
<div><a href="{{ path('app_admin_users') }}" class="btn btn-primary">Konta użytkowników</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col card">
|
||||
<div class="card-body">
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends 'admin/index.html.twig' %}
|
||||
{% block content %}
|
||||
{% if plainPassword is null %}
|
||||
{{ form(form) }}
|
||||
{% else %}
|
||||
<div class="alert alert-success">
|
||||
Utworzono użytkownika!<br>
|
||||
Login: {{ user.username }}<br>
|
||||
Hasło: {{ plainPassword }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends 'admin/index.html.twig' %}
|
||||
{% block content %}
|
||||
<div class="form-check form-switch">
|
||||
<input type="checkbox" class="form-check-input" id="switch{{ permissionAll.case.value }}"
|
||||
{% if user.isGranted(permissionAll.case) %}checked{% endif %}
|
||||
disabled
|
||||
>
|
||||
<label class="form-check-label" for="switch{{ permissionAll.case.value }}">{{ permissionAll.case.takeLang }}</label>
|
||||
</div>
|
||||
<form action="{{ path('app_admin_user_edit',{id:user.id}) }}" method="post">
|
||||
<input type="hidden" name="token" value="{{ csrf_token('admin-user-edit-permission') }}">
|
||||
{% for permissionOverall in permissionAll.children %}
|
||||
<div style="padding-left: 30px;">
|
||||
<div class="form-check form-switch">
|
||||
<input type="checkbox" class="form-check-input" id="switch{{ permissionOverall.case.value }}" name="{{ permissionOverall.case.value }}"
|
||||
{% if user.isGranted(permissionOverall.case) %}checked{% endif %}
|
||||
onchange="this.form.submit()"
|
||||
>
|
||||
<label class="form-check-label" for="switch{{ permissionOverall.case.value }}">{{ permissionOverall.case.takeLang }}</label>
|
||||
</div>
|
||||
{% for permissions in permissionOverall.children %}
|
||||
<div style="padding-left: 30px;">
|
||||
<div class="form-check form-switch">
|
||||
<input type="checkbox" class="form-check-input" id="switch{{ permissions.value }}" name="{{ permissions.value }}"
|
||||
{% if user.isGranted(permissions) %}checked{% endif %}
|
||||
onchange="this.form.submit()"
|
||||
>
|
||||
<label class="form-check-label" for="switch{{ permissions.value }}">{{ permissions.takeLang }}</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,65 @@
|
||||
{% extends 'admin/index.html.twig' %}
|
||||
{% block content %}
|
||||
<div class="page admin users" data-controller="admin-users">
|
||||
<a href="{{ path('app_admin_user_add') }}" class="btn btn-success">Dodaj użytkownika</a>
|
||||
<table class="table table-hover table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<td>Nazwa</td>
|
||||
<td>Uprawnienia</td>
|
||||
<td>Reset hasła</td>
|
||||
<td>Usuń</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>
|
||||
{% for role in user.getEnumRoles %}
|
||||
{{ role.takeLang }},
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ path('app_admin_user_edit',{id:user.id}) }}" class="btn btn-success">Edytuj Uprawnienia</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ path('app_admin_user_add_success',{id:user.id}) }}" class="btn btn-primary">Reset hasła</a>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger confirmRemoveUser"
|
||||
type="button"
|
||||
data-username="{{ user.username }}"
|
||||
data-formlink="{{ path('app_admin_user_remove',{id:user.id}) }}"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#removeConfirmModal"
|
||||
>Usuń</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="modal fade" id="removeConfirmModal" tabindex="-1" aria-labelledby="removeConfirmModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="removeConfirmModalLabel">Czy na pewno chcesz usunąć konto <strong class="insertUsername"></strong>?</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h3>Tej operacji nie można cofnąć!</h3>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="token" value="{{ csrf_token('admin-remove-user') }}">
|
||||
<button type="submit" class="btn btn-danger">Usuń</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,19 @@
|
||||
{% extends 'admin/index.html.twig' %}
|
||||
{% block content %}
|
||||
<div class="alert alert-success">
|
||||
{% if newUser %}
|
||||
<h4 class="alert-heading">
|
||||
Poprawnie dodano nowego użytkownia!
|
||||
</h4>
|
||||
<p>
|
||||
Nazwa nowego użytkownika: <strong>{{ user.username }}</strong>
|
||||
</p>
|
||||
<hr>
|
||||
{% endif %}
|
||||
<p class="mb-0">
|
||||
Link do wygenerowania hasła:
|
||||
<input type="text" value="{{ activationLink }}" class="form-control">
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -25,7 +25,13 @@
|
||||
</div>
|
||||
{# <img src="..." class="card-img-top" alt="...">#}
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><a href="{{ path('app_client',{id: report.client.id}) }}" class="link-{{ reports.status.linkColor }}">{{ report.client.strName }}</a></h5>
|
||||
<h5 class="card-title">
|
||||
{% if is_granted('clientView') %}
|
||||
<a href="{{ path('app_client',{id: report.client.id}) }}" class="link-{{ reports.status.linkColor }}">{{ report.client.strName }}</a>
|
||||
{% else %}
|
||||
{{ report.client.strName }}
|
||||
{% endif %}
|
||||
</h5>
|
||||
{# <h6 class="card-subtitle text-muted">Numer sprawozdania: </h6>#}
|
||||
<div class="card-text">
|
||||
<form action="{{ path('app_set_status_todo') }}" method="post">
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
<div class="card text-white bg-{{ schedule.getStatus.backgroundColor }}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<a href="{{ path('app_client',{id: schedule.client.id}) }}" class="link-dark">{{ schedule.client.strName }}</a>
|
||||
{% if is_granted('clientView') %}
|
||||
<a href="{{ path('app_client',{id: schedule.client.id}) }}" class="link-dark">{{ schedule.client.strName }}</a>
|
||||
{% else %}
|
||||
<div class="link-dark">{{ schedule.client.strName }}</div>
|
||||
{% endif %}
|
||||
</h5>
|
||||
<h6 class="card-subtitle text-muted">Pozostały czas: {{ schedule.getTimeLeft }} dni</h6>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Nowe hasło{% endblock %}
|
||||
{% block navigation %}{% endblock %}
|
||||
{% block body %}
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col col-lg-4">
|
||||
{% if user is not null %}
|
||||
<div class="alert alert-success">
|
||||
<h4 class="alert-heading">
|
||||
Wygenerowano nowe hasło!
|
||||
</h4>
|
||||
<p>
|
||||
Twoja nazwa użytkownika: <strong>{{ user.username }}</strong>
|
||||
</p>
|
||||
<p>
|
||||
Twoje nowe hasło: <strong>{{ newPassword }}</strong>
|
||||
</p>
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
Zapisz dane logowania. Jeśli je zgubisz, będziesz potrzebować nowego linku aktywacyjnego od administratora!
|
||||
</p>
|
||||
<hr>
|
||||
<p class="mb-0">
|
||||
<a href="{{ path('app_login') }}" class="btn btn-success">Zaloguj się</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger">
|
||||
<p>Błędny kod aktywacyjny! Skontaktuj się z administratorem!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user