Ajout du bundle password reset + configuration bootstrap

main
mirakinparis 3 years ago
parent a7e977fa94
commit e813480de5
  1. 7
      assets/app.js
  2. 2
      assets/bootstrap.js
  3. 2
      assets/controllers/hello_controller.js
  4. 2
      composer.json
  5. 2
      composer.lock
  6. 2
      config/bundles.php
  7. 3
      config/packages/reset_password.yaml
  8. 25
      config/packages/webpack_encore.yaml
  9. 165
      package-lock.json
  10. 5
      package.json
  11. 177
      src/Controller/ResetPasswordController.php
  12. 20
      src/Repository/ResetPasswordRequestRepository.php
  13. 4
      symfony.lock
  14. 91
      templates/base.html.twig
  15. 6
      templates/reset_password/request.html.twig
  16. 13
      webpack.config.js

@ -5,8 +5,13 @@
* (and its CSS file) in your base layout (base.html.twig).
*/
// any CSS you import will output into a single css file (app.css in this case)
import './styles/app.css';
import './styles/app.scss';
import 'bootstrap';
import bsCustomFileInput from 'bs-custom-file-input';
// start the Stimulus application
import './bootstrap';
bsCustomFileInput.init();

@ -4,7 +4,7 @@ import { startStimulusApp } from '@symfony/stimulus-bridge';
export const app = startStimulusApp(require.context(
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
true,
/\.(j|t)sx?$/
/\.[jt]sx?$/
));
// register any custom, 3rd party controllers here

@ -1,4 +1,4 @@
import { Controller } from 'stimulus';
import { Controller } from '@hotwired/stimulus';
/*
* This is an example Stimulus controller!

@ -21,7 +21,7 @@
"symfony/security-bundle": "5.4.*",
"symfony/webpack-encore-bundle": "^1.17",
"symfony/yaml": "5.4.*",
"symfonycasts/reset-password-bundle": "^1.9"
"symfonycasts/reset-password-bundle": "^1.17"
},
"config": {
"preferred-install": {

2
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6ee8595e2df24ee2fb0f31140be0809f",
"content-hash": "457231c539da13cd02b9ab62ed7b1da1",
"packages": [
{
"name": "composer/package-versions-deprecated",

@ -12,6 +12,6 @@ return [
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
];

@ -1,5 +1,2 @@
symfonycasts_reset_password:
request_password_repository: App\Repository\ResetPasswordRequestRepository
lifetime: 3600
throttle_limit: 5
enable_garbage_collection: true

@ -7,7 +7,12 @@ webpack_encore:
# Set attributes that will be rendered on all script and link tags
script_attributes:
defer: true
# Uncomment (also under link_attributes) if using Turbo Drive
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
# 'data-turbo-track': reload
# link_attributes:
# Uncomment if using Turbo Drive
# 'data-turbo-track': reload
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
# crossorigin: 'anonymous'
@ -20,11 +25,21 @@ webpack_encore:
# If you have multiple builds:
# builds:
# pass "frontend" as the 3rg arg to the Twig functions
# frontend: '%kernel.project_dir%/public/frontend/build'
# pass the build name as the 3rd argument to the Twig functions
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
# frontend: '%kernel.project_dir%/public/frontend/build'
framework:
assets:
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
#when@prod:
# webpack_encore:
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# # Available in version 1.2
# cache: true
# Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
# Put in config/packages/prod/webpack_encore.yaml
# cache: true
#when@test:
# webpack_encore:
# strict_mode: false

165
package-lock.json generated

@ -9,10 +9,15 @@
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.0",
"@hotwired/stimulus": "^3.0.0",
"@popperjs/core": "^2.11.8",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^4.0.0",
"bootstrap": "^5.3.0",
"bs-custom-file-input": "^1.3.4",
"core-js": "^3.23.0",
"regenerator-runtime": "^0.13.9",
"sass": "^1.62.1",
"sass-loader": "^13.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-notifier": "^1.15.0"
@ -1910,6 +1915,16 @@
"webpack": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
@ -3017,6 +3032,25 @@
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
"node_modules/bootstrap": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
"integrity": "sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"peerDependencies": {
"@popperjs/core": "^2.11.7"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -3067,6 +3101,15 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
"node_modules/bs-custom-file-input": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz",
"integrity": "sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@ -4721,6 +4764,12 @@
"postcss": "^8.1.0"
}
},
"node_modules/immutable": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
"dev": true
},
"node_modules/import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@ -5131,6 +5180,15 @@
"node": ">=0.10.0"
}
},
"node_modules/klona": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
"integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/launch-editor": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz",
@ -6760,6 +6818,61 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"node_modules/sass": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-loader": {
"version": "13.3.1",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz",
"integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==",
"dev": true,
"dependencies": {
"klona": "^2.0.6",
"neo-async": "^2.6.2"
},
"engines": {
"node": ">= 14.15.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"fibers": ">= 3.1.0",
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
"sass": "^1.3.0",
"sass-embedded": "*",
"webpack": "^5.0.0"
},
"peerDependenciesMeta": {
"fibers": {
"optional": true
},
"node-sass": {
"optional": true
},
"sass": {
"optional": true
},
"sass-embedded": {
"optional": true
}
}
},
"node_modules/schema-utils": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz",
@ -9342,6 +9455,12 @@
"string-width": "^4.2.3"
}
},
"@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"dev": true
},
"@sinclair/typebox": {
"version": "0.25.24",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz",
@ -10176,6 +10295,13 @@
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
"bootstrap": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
"integrity": "sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw==",
"dev": true,
"requires": {}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -10207,6 +10333,12 @@
"update-browserslist-db": "^1.0.10"
}
},
"bs-custom-file-input": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bs-custom-file-input/-/bs-custom-file-input-1.3.4.tgz",
"integrity": "sha512-NBsQzTnef3OW1MvdKBbMHAYHssCd613MSeJV7z2McXznWtVMnJCy7Ckyc+PwxV6Pk16cu6YBcYWh/ZE0XWNKCA==",
"dev": true
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@ -11436,6 +11568,12 @@
"dev": true,
"requires": {}
},
"immutable": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
"integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
"dev": true
},
"import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@ -11727,6 +11865,12 @@
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"klona": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
"integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
"dev": true
},
"launch-editor": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz",
@ -12884,6 +13028,27 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"sass": {
"version": "1.62.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz",
"integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
}
},
"sass-loader": {
"version": "13.3.1",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.1.tgz",
"integrity": "sha512-cBTxmgyVA1nXPvIK4brjJMXOMJ2v2YrQEuHqLw3LylGb3gsR6jAvdjHMcy/+JGTmmIF9SauTrLLR7bsWDMWqgg==",
"dev": true,
"requires": {
"klona": "^2.0.6",
"neo-async": "^2.6.2"
}
},
"schema-utils": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz",

@ -3,10 +3,15 @@
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.0",
"@hotwired/stimulus": "^3.0.0",
"@popperjs/core": "^2.11.8",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^4.0.0",
"bootstrap": "^5.3.0",
"bs-custom-file-input": "^1.3.4",
"core-js": "^3.23.0",
"regenerator-runtime": "^0.13.9",
"sass": "^1.62.1",
"sass-loader": "^13.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-notifier": "^1.15.0"

@ -1,177 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\ChangePasswordFormType;
use App\Form\ResetPasswordRequestFormType;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
/**
* @Route("/reset-password")
*/
class ResetPasswordController extends AbstractController
{
use ResetPasswordControllerTrait;
private $resetPasswordHelper;
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper)
{
$this->resetPasswordHelper = $resetPasswordHelper;
}
/**
* Display & process form to request a password reset.
*
* @Route("", name="app_forgot_password_request")
*/
public function request(Request $request, MailerInterface $mailer): Response
{
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->processSendingPasswordResetEmail(
$form->get('email')->getData(),
$mailer
);
}
return $this->render('reset_password/request.html.twig', [
'requestForm' => $form->createView(),
]);
}
/**
* Confirmation page after a user has requested a password reset.
*
* @Route("/check-email", name="app_check_email")
*/
public function checkEmail(): Response
{
// Generate a fake token if the user does not exist or someone hit this page directly.
// This prevents exposing whether or not a user was found with the given email address or not
if (null === ($resetToken = $this->getTokenObjectFromSession())) {
$resetToken = $this->resetPasswordHelper->generateFakeResetToken();
}
return $this->render('reset_password/check_email.html.twig', [
'resetToken' => $resetToken,
]);
}
/**
* Validates and process the reset URL that the user clicked in their email.
*
* @Route("/reset/{token}", name="app_reset_password")
*/
public function reset(Request $request, UserPasswordEncoderInterface $passwordEncoder, string $token = null): Response
{
if ($token) {
// We store the token in session and remove it from the URL, to avoid the URL being
// loaded in a browser and potentially leaking the token to 3rd party JavaScript.
$this->storeTokenInSession($token);
return $this->redirectToRoute('app_reset_password');
}
$token = $this->getTokenFromSession();
if (null === $token) {
throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
}
try {
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
} catch (ResetPasswordExceptionInterface $e) {
$this->addFlash('reset_password_error', sprintf(
'There was a problem validating your reset request - %s',
$e->getReason()
));
return $this->redirectToRoute('app_forgot_password_request');
}
// The token is valid; allow the user to change their password.
$form = $this->createForm(ChangePasswordFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// A password reset token should be used only once, remove it.
$this->resetPasswordHelper->removeResetRequest($token);
// Encode the plain password, and set it.
$encodedPassword = $passwordEncoder->encodePassword(
$user,
$form->get('plainPassword')->getData()
);
$user->setPassword($encodedPassword);
$this->getDoctrine()->getManager()->flush();
// The session is cleaned up after the password has been changed.
$this->cleanSessionAfterReset();
return $this->redirectToRoute('app_home');
}
return $this->render('reset_password/reset.html.twig', [
'resetForm' => $form->createView(),
]);
}
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer): RedirectResponse
{
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy([
'email' => $emailFormData,
]);
// Do not reveal whether a user account was found or not.
if (!$user) {
return $this->redirectToRoute('app_check_email');
}
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (ResetPasswordExceptionInterface $e) {
// If you want to tell the user why a reset email was not sent, uncomment
// the lines below and change the redirect to 'app_forgot_password_request'.
// Caution: This may reveal if a user is registered or not.
//
// $this->addFlash('reset_password_error', sprintf(
// 'There was a problem handling your password reset request - %s',
// $e->getReason()
// ));
return $this->redirectToRoute('app_check_email');
}
$email = (new TemplatedEmail())
->from(new Address('k.jouini@tyr.local', 'SfyCAS Mail Bot'))
->to($user->getEmail())
->subject('Your password reset request')
->htmlTemplate('reset_password/email.html.twig')
->context([
'resetToken' => $resetToken,
])
;
$mailer->send($email);
// Store the token object in session for retrieval in check-email route.
$this->setTokenObjectInSession($resetToken);
return $this->redirectToRoute('app_check_email');
}
}

@ -10,6 +10,8 @@ use SymfonyCasts\Bundle\ResetPassword\Persistence\Repository\ResetPasswordReques
use SymfonyCasts\Bundle\ResetPassword\Persistence\ResetPasswordRequestRepositoryInterface;
/**
* @extends ServiceEntityRepository<ResetPasswordRequest>
*
* @method ResetPasswordRequest|null find($id, $lockMode = null, $lockVersion = null)
* @method ResetPasswordRequest|null findOneBy(array $criteria, array $orderBy = null)
* @method ResetPasswordRequest[] findAll()
@ -24,6 +26,24 @@ class ResetPasswordRequestRepository extends ServiceEntityRepository implements
parent::__construct($registry, ResetPasswordRequest::class);
}
public function add(ResetPasswordRequest $entity, bool $flush = false): void
{
$this->getEntityManager()->persist($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function remove(ResetPasswordRequest $entity, bool $flush = false): void
{
$this->getEntityManager()->remove($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function createResetPasswordRequest(object $user, \DateTimeInterface $expiresAt, string $selector, string $hashedToken): ResetPasswordRequestInterface
{
return new ResetPasswordRequest($user, $expiresAt, $selector, $hashedToken);

@ -478,10 +478,10 @@
"version": "v5.0.11"
},
"symfonycasts/reset-password-bundle": {
"version": "1.0",
"version": "1.17",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "master",
"branch": "main",
"version": "1.0",
"ref": "97c1627c0384534997ae1047b93be517ca16de43"
},

@ -1,19 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}Welcome!{% endblock %}</title>
{# Run `composer require symfony/webpack-encore-bundle`
and uncomment the following Encore helpers to start using Symfony UX #}
{% block stylesheets %}
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,500,500i,600,600i&display=swap" rel="stylesheet" />
{{ encore_entry_link_tags('app') }}
{% endblock %}
</head>
<body>
<header class="header">
<h1 class="sr-only">
Symfony sandbox
</h1>
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-expand-xl navbar-light bg-light">
<div class="container mt-4 mb-3">
<a class="navbar-brand mr-4 pr-2" href="{{ path('app_home') }}">
&#128217; Home
</a>
<button class="navbar-toggler border-0" type="button" data-toggle="collapse" data-target="#header-menu" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Show/Hide navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="header-menu">
<ul class="navbar-nav ml-auto">
<li class="nav-item mr-3">
<a class="nav-link" href="{{ path('app_home') }}">
Import
</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse" id="header-menu">
<ul class="navbar-nav ml-auto">
<li class="nav-item mr-3">
<a class="nav-link" href="">
Export
</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse" id="header-menu">
<ul class="navbar-nav ml-auto">
<li class="nav-item mr-3">
<a class="nav-link" href="{{ path('app_home') }}">
Admin
</a>
</li>
</ul>
</div>
</div>
</nav>
<nav class="bg-light border-bottom">
<div class="container">
{# render_esi(path('conference_header')) #}
</div>
</nav>
</header>
<main role="main" class="container mt-5">
{% block body %}{% endblock %}
</body>
</main>
<footer class="mt-7 px-3 py-5 text-center text-muted">
<p>
Symfony sandbox
</p>
<p>
<a href="#" class="text-white">Back to top</a>
</p>
</footer>
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</body>
</html>

@ -3,8 +3,8 @@
{% block title %}Reset your password{% endblock %}
{% block body %}
{% for flashError in app.flashes('reset_password_error') %}
<div class="alert alert-danger" role="alert">{{ flashError }}</div>
{% for flash_error in app.flashes('reset_password_error') %}
<div class="alert alert-danger" role="alert">{{ flash_error }}</div>
{% endfor %}
<h1>Reset your password</h1>
@ -12,7 +12,7 @@
{{ form_row(requestForm.email) }}
<div>
<small>
Enter your email address and we we will send you a
Enter your email address and we will send you a
link to reset your password.
</small>
</div>

@ -11,7 +11,7 @@ Encore
.setOutputPath('public/build/')
// public path used by the web server to access the output path
.setPublicPath('/build')
// only needed for CDN's or sub-directory deploy
// only needed for CDN's or subdirectory deploy
//.setManifestKeyPrefix('build/')
/*
@ -45,14 +45,15 @@ Encore
// enables hashed filenames (e.g. app.abc123.css)
.enableVersioning(Encore.isProduction())
.configureBabel((config) => {
config.plugins.push('@babel/plugin-proposal-class-properties');
})
// configure Babel
// .configureBabel((config) => {
// config.plugins.push('@babel/a-babel-plugin');
// })
// enables @babel/preset-env polyfills
// enables and configure @babel/preset-env polyfills
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
config.corejs = '3.23';
})
// enables Sass/SCSS support

Loading…
Cancel
Save