mirror of
https://forge.chapril.org/tykayn/caisse-bliss
synced 2025-06-20 01:44:42 +02:00
up login
This commit is contained in:
parent
d8c1b7c0f6
commit
d01ecdabba
13 changed files with 198 additions and 25 deletions
|
@ -9,6 +9,11 @@ body {
|
|||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.masthead-avatar {
|
||||
width: 2rem;
|
||||
max-height: 2rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
min-height: 100vh;
|
||||
|
@ -30,6 +35,7 @@ body {
|
|||
.bg-img {
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
background-position: center;
|
||||
min-height: 100vh;
|
||||
|
@ -37,12 +43,13 @@ body {
|
|||
|
||||
.bg-accessories {
|
||||
@extend .bg-img;
|
||||
// background-image: url('img/accessories.jpg');
|
||||
// background-image: url('assets/img/accessories.jpg');
|
||||
}
|
||||
|
||||
.bg-girl {
|
||||
@extend .bg-img;
|
||||
// background-image: url('img/girl_computer.jpg');
|
||||
// background-image: url('../img/girl_computer.jpg');
|
||||
// background-image: url('assets/img/girl_computer.jpg');
|
||||
}
|
||||
|
||||
.bg-color {
|
||||
|
|
|
@ -1,33 +1,36 @@
|
|||
# config/packages/security.yaml
|
||||
security:
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
# Hashers pour les mots de passe
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||
App\Entity\User:
|
||||
algorithm: auto
|
||||
|
||||
# Fournisseurs d'utilisateurs
|
||||
providers:
|
||||
# used to reload user from session & other features (e.g. switch_user)
|
||||
app_user_provider:
|
||||
entity:
|
||||
class: App\Entity\User
|
||||
property: email
|
||||
|
||||
# Firewalls
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
main:
|
||||
lazy: true
|
||||
provider: app_user_provider
|
||||
form_login:
|
||||
# "app_login" is the name of the route created previously
|
||||
login_path: app_login
|
||||
check_path: app_login
|
||||
# access_token:
|
||||
# token_handler: App\Security\AccessTokenHandler
|
||||
|
||||
# activate different ways to authenticate
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
|
||||
# Easy way to control access for large sections of your site
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
# Contrôle d'accès
|
||||
access_control:
|
||||
- { path: ^/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/logged, roles: ROLE_USER }
|
||||
# - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Autoriser l'accès à la page de connexion
|
||||
# - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Autoriser l'accès anonyme à toutes les autres pages
|
||||
|
||||
when@test:
|
||||
security:
|
||||
|
|
|
@ -25,3 +25,7 @@ services:
|
|||
Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
|
||||
arguments:
|
||||
- '%env(DATABASE_URL)%'
|
||||
|
||||
App\Filter\UserProductsFilter:
|
||||
arguments: [ '@security.helper' ]
|
||||
tags: [ 'api_platform.filter' ]
|
18
src/Controller/LoginController.php
Normal file
18
src/Controller/LoginController.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
final class LoginController extends AbstractController
|
||||
{
|
||||
#[Route('/login', name: 'app_login')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('login/index.html.twig', [
|
||||
'controller_name' => 'LoginController',
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -25,8 +25,9 @@ class SecurityController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route(path: '/logout', name: 'app_logout')]
|
||||
public function logout(): void
|
||||
public function logout(): Response
|
||||
{
|
||||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||
return $this->redirectToRoute('app_default');
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,17 @@
|
|||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\ApiProperty;
|
||||
|
||||
use App\Repository\ProductRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use App\Filter\UserProductsFilter;
|
||||
use App\DTO\UserDTO;
|
||||
|
||||
#[ApiResource(paginationEnabled: false)]
|
||||
#[UserProductsFilter]
|
||||
#[ORM\Entity(repositoryClass: ProductRepository::class)]
|
||||
class Product
|
||||
{
|
||||
|
@ -30,12 +35,14 @@ class Product
|
|||
* @var Collection<int, GroupOfProducts>
|
||||
*/
|
||||
#[ORM\ManyToMany(targetEntity: GroupOfProducts::class, mappedBy: 'products')]
|
||||
#[ApiProperty(readable: false)]
|
||||
private Collection $groupOfProducts;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Selling>
|
||||
*/
|
||||
#[ORM\ManyToMany(targetEntity: Selling::class, mappedBy: 'products')]
|
||||
#[ApiProperty(readable: false)]
|
||||
private Collection $sellings;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'products')]
|
||||
|
|
27
src/EventSubscriber/NotShownCountSubscriber.php
Normal file
27
src/EventSubscriber/NotShownCountSubscriber.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace App\EventSubscriber;
|
||||
|
||||
use ApiPlatform\Symfony\EventListener\EventPriorities;
|
||||
use ApiPlatform\EventListener\FilterCollectionEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
final class NotShownCountSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
FilterCollectionEvent::class => ['addNotShownCount', EventPriorities::PRE_WRITE],
|
||||
];
|
||||
}
|
||||
|
||||
public function addNotShownCount(FilterCollectionEvent $event): void
|
||||
{
|
||||
$context = $event->getContext();
|
||||
if (isset($context['notShownCount'])) {
|
||||
$event->getResponse()->setData(array_merge($event->getResponse()->getData(), [
|
||||
'notShownCount' => $context['notShownCount'],
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
52
src/Filter/UserProductsFilter.php
Normal file
52
src/Filter/UserProductsFilter.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* filtrer les objets selon ceux qui appartiennent uniquement à l'utilisateur connecté
|
||||
*/
|
||||
namespace App\Filter;
|
||||
|
||||
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\Metadata\FilterInterface;
|
||||
|
||||
final class UserProductsFilter extends AbstractFilter implements FilterInterface
|
||||
{
|
||||
private $security;
|
||||
|
||||
public function __construct(Security $security)
|
||||
{
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
|
||||
{
|
||||
if ($property === 'user' && $this->security->isGranted('ROLE_USER')) {
|
||||
$user = $this->security->getUser();
|
||||
$queryBuilder->andWhere('o.user = :user')->setParameter('user', $user);
|
||||
|
||||
// Compter le nombre total de produits pour l'utilisateur
|
||||
$totalProducts = $queryBuilder->getEntityManager()->getRepository('App\Entity\Product')->count(['user' => $user]);
|
||||
$filteredProducts = $queryBuilder->getQuery()->getResult();
|
||||
$notShownCount = $totalProducts - count($filteredProducts);
|
||||
|
||||
// Ajouter le nombre de produits non montrés au contexte
|
||||
$context['notShownCount'] = $notShownCount;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDescription(string $resourceClass): array
|
||||
{
|
||||
return [
|
||||
'user' => [
|
||||
'property' => 'user',
|
||||
'type' => 'string',
|
||||
'required' => false,
|
||||
'swagger' => [
|
||||
'description' => 'Filtrer les produits par utilisateur connecté',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
30
src/Security/AccessTokenHandler.php
Normal file
30
src/Security/AccessTokenHandler.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Repository\AccessTokenRepository;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Http\AccessToken\AccessTokenHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
|
||||
class AccessTokenHandler implements AccessTokenHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private AccessTokenRepository $repository
|
||||
) {
|
||||
}
|
||||
|
||||
public function getUserBadgeFrom(string $accessToken): UserBadge
|
||||
{
|
||||
// e.g. query the "access token" database to search for this token
|
||||
$accessToken = $this->repository->findOneByValue($accessToken);
|
||||
if (null === $accessToken || !$accessToken->isValid()) {
|
||||
throw new BadCredentialsException('Invalid credentials.');
|
||||
}
|
||||
|
||||
// and return a UserBadge object containing the user identifier from the found token
|
||||
// (this is the same identifier used in Security configuration; it can be an email,
|
||||
// a UUID, a username, a database ID, etc.)
|
||||
return new UserBadge($accessToken->getUserId());
|
||||
}
|
||||
}
|
|
@ -32,13 +32,16 @@
|
|||
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="/#contact">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% include 'default/login-choices.html.twig' %}
|
||||
</div>
|
||||
|
||||
|
||||
</nav>
|
||||
<!-- Masthead-->
|
||||
<header class="masthead bg-primary text-white text-center">
|
||||
<div class="container d-flex align-items-center flex-column">
|
||||
<!-- Masthead Avatar Image-->
|
||||
<img class="masthead-avatar mb-5" src="assets/img/avataaars.svg" alt="..." />
|
||||
<img class="masthead-avatar mb-5" width="2rem" src="/img/avataaars.svg" alt="..." />
|
||||
<!-- Masthead Heading-->
|
||||
<h1 class="masthead-heading text-uppercase mb-0">Caisse Bliss</h1>
|
||||
<!-- Icon Divider-->
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
|
||||
{% include 'default/login-choices.html.twig' %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-elements">
|
||||
|
|
|
@ -7,15 +7,16 @@
|
|||
{% block body %}
|
||||
<div class="main-screen" id="homepage">
|
||||
<div id="welcome">
|
||||
<section class="bg-accessories" style="background : url('img/accessories.jpg')">
|
||||
|
||||
<section class="bg-accessories"
|
||||
style=" background-image: url('/img/accessories.jpg') ">
|
||||
|
||||
{# <img src="img/accessories.jpg" alt="accesoires">#}
|
||||
<div class="bg-shader">
|
||||
<div class="container main-section">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 padded-v">
|
||||
<h1 class="text-center">
|
||||
{#<i class="fa fa-circle-o-notch logo-main"></i>#}
|
||||
<i class="fa fa-circle-o-notch logo-main"></i>
|
||||
{% trans %}menu.title{% endtrans %}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
20
templates/login/index.html.twig
Normal file
20
templates/login/index.html.twig
Normal file
|
@ -0,0 +1,20 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Hello LoginController!{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<style>
|
||||
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
|
||||
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
|
||||
</style>
|
||||
|
||||
<div class="example-wrapper">
|
||||
<h1>Hello {{ controller_name }}! ✅</h1>
|
||||
|
||||
This friendly message is coming from:
|
||||
<ul>
|
||||
<li>Your controller at <code>/home/poule/encrypted/stockage-syncable/www/development/html/caisse-bliss/src/Controller/LoginController.php</code></li>
|
||||
<li>Your template at <code>/home/poule/encrypted/stockage-syncable/www/development/html/caisse-bliss/templates/login/index.html.twig</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue