diff --git a/.eslintrc b/.eslintrc
index e4d7e93..1fdc77e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -2,9 +2,7 @@
"extends": [
// add more generic rulesets here, such as:
"eslint:recommended",
- "airbnb-base",
- "plugin:vue/recommended",
- "plugin:vue/vue3-recommended"
+ "airbnb-base"
],
"parserOptions": {
"parser": "espree",
@@ -13,35 +11,13 @@
},
"env": {
"es6": true,
- "browser": true,
- "vue/setup-compiler-macros": true
+ "browser": true
},
"rules": {
"semi": [
"error",
"never"
],
- "vue/no-v-html": "off",
- "vue/html-indent": [
- "error",
- "tab"
- ],
- "vue/html-closing-bracket-spacing": [
- "error",
- {
- "startTag": "never",
- "endTag": "never",
- "selfClosingTag": "never"
- }
- ],
- "vue/component-api-style": [
- "error",
- [
- "script-setup",
- "composition"
- ]
- // "script-setup", "composition", "composition-vue2", or "options"
- ],
"indent": [
"error",
"tab"
diff --git a/.gitignore b/.gitignore
index 960323f..dd24a2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ yarn-error.log
/public/media/cache/
###< liip/imagine-bundle ###
/tools/php-cs-fixer/vendor/
+/public/uploads/
diff --git a/TODO b/TODO
index 4c64e39..b663457 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
accent color #d43934
-remove vue
-use bootsrap
+merge RequestController/SecurityController
+don't use html in easyadmin / quotes
use turbo
make unit tests
diff --git a/assets/js/index.js b/assets/js/index.js
index 04da20b..0956617 100644
--- a/assets/js/index.js
+++ b/assets/js/index.js
@@ -9,9 +9,9 @@ import 'bootswatch/dist/slate/bootstrap.min.css'
$(document).ready(function () {
console.log('ready')
$('#toggleSidebar').on('click', function () {
- $('#toggleIcon').toggleClass('fa fa-lg fa-fw fa-caret-square-o-left')
- $('#toggleIcon').toggleClass('fa fa-lg fa-fw fa-caret-square-o-right')
+ let toggleIcon = $('#toggleIcon')
+ toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-left')
+ toggleIcon.toggleClass('fa fa-lg fa-fw fa-caret-square-o-right')
$('#sidebar').toggleClass('active')
})
})
-
diff --git a/assets/styles/app.scss b/assets/styles/app.scss
index 6136035..da8b002 100644
--- a/assets/styles/app.scss
+++ b/assets/styles/app.scss
@@ -15,7 +15,7 @@
}
-html, body{
+html, body {
margin: 0;
padding: 0;
//background: linear-gradient(90deg, rgba(14,14,16,1) 0%, rgba(255,128,64,1) 35%, rgba(14,14,16,1) 100%);
@@ -35,6 +35,7 @@ $jet-black: #0e0e10;
#sidebar {
min-width: 180px;
max-width: 180px;
+ height: 100%;
display: inline;
white-space: nowrap;
overflow: hidden;
@@ -54,3 +55,44 @@ $jet-black: #0e0e10;
display: none;
}
+#main_content {
+ overflow-y: auto;
+ height: calc(100vh - 160px)
+}
+
+.form-signin {
+ width: 100%;
+ max-width: 330px;
+ padding: 15px;
+ margin: 50px auto auto;
+}
+
+.form-signin .checkbox {
+ font-weight: 400;
+}
+
+.form-signin .form-control {
+ position: relative;
+ box-sizing: border-box;
+ height: auto;
+ padding: 10px;
+ font-size: 16px;
+}
+
+.form-signin .form-control:focus {
+ z-index: 2;
+}
+
+.form-signin input {
+ border-radius: 0;
+}
+
+.form-signin input[id="registration_form_username"] {
+ margin-bottom: -1px;
+ border-radius: 0.375rem 0.375rem 0 0;
+}
+
+.form-signin input[id="registration_form_password_second"] {
+ margin-bottom: 10px;
+ border-radius: 0 0 0.375rem 0.375rem;
+}
diff --git a/composer.json b/composer.json
index 47e9519..b5dce4c 100644
--- a/composer.json
+++ b/composer.json
@@ -7,7 +7,6 @@
"php": ">=8.1.0",
"ext-ctype": "*",
"ext-iconv": "*",
- "api-platform/core": "^2.6",
"doctrine/annotations": "^1.0",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.2",
@@ -42,6 +41,7 @@
"symfony/proxy-manager-bridge": "6.1.*",
"symfony/runtime": "6.1.*",
"symfony/security-bundle": "6.1.*",
+ "symfony/security-csrf": "6.1.*",
"symfony/serializer": "6.1.*",
"symfony/string": "6.1.*",
"symfony/translation": "6.1.*",
@@ -51,8 +51,11 @@
"symfony/webapp-meta": "^1.0",
"symfony/webpack-encore-bundle": "^1.14",
"symfony/yaml": "6.1.*",
+ "symfonycasts/reset-password-bundle": "^1.16",
+ "symfonycasts/verify-email-bundle": "^1.12",
+ "twig/extra-bundle": "^3.4",
"twig/markdown-extra": "^3.4",
- "twig/twig": "3.3.10"
+ "twig/twig": "3.4.*"
},
"config": {
"allow-plugins": {
diff --git a/composer.lock b/composer.lock
index 88bf074..1828b59 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,177 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "efcbee99aa768ee1aa5bde178db4a11b",
+ "content-hash": "7d3d3e0369d1f8799e53d7d078431c55",
"packages": [
- {
- "name": "api-platform/core",
- "version": "v2.7.2",
- "source": {
- "type": "git",
- "url": "https://github.com/api-platform/core.git",
- "reference": "80c3f3c38b9ac234bde0cbc2b77d6628326bdefc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/api-platform/core/zipball/80c3f3c38b9ac234bde0cbc2b77d6628326bdefc",
- "reference": "80c3f3c38b9ac234bde0cbc2b77d6628326bdefc",
- "shasum": ""
- },
- "require": {
- "doctrine/inflector": "^1.0 || ^2.0",
- "php": ">=7.1",
- "psr/cache": "^1.0 || ^2.0 || ^3.0",
- "psr/container": "^1.0 || ^2.0",
- "symfony/deprecation-contracts": "^2.1 || ^3.0",
- "symfony/http-foundation": "^4.4 || ^5.1 || ^6.0",
- "symfony/http-kernel": "^4.4 || ^5.1 || ^6.0",
- "symfony/property-access": "^3.4.19 || ^4.4 || ^5.1 || ^6.0",
- "symfony/property-info": "^3.4 || ^4.4 || ^5.2.1 || ^6.0",
- "symfony/serializer": "^4.4 || ^5.1 || ^6.0",
- "symfony/web-link": "^4.4 || ^5.1 || ^6.0",
- "willdurand/negotiation": "^2.0.3 || ^3.0"
- },
- "conflict": {
- "doctrine/common": "<2.7",
- "doctrine/dbal": "<2.10",
- "doctrine/mongodb-odm": "<2.2",
- "doctrine/persistence": "<1.3",
- "elasticsearch/elasticsearch": ">=8.0"
- },
- "require-dev": {
- "behat/behat": "^3.1",
- "behat/mink": "^1.9@dev",
- "doctrine/annotations": "^1.7",
- "doctrine/cache": "^1.11 || ^2.1",
- "doctrine/common": "^2.11 || ^3.0",
- "doctrine/data-fixtures": "^1.2.2",
- "doctrine/dbal": "^2.6 || ^3.0",
- "doctrine/doctrine-bundle": "^1.12 || ^2.0",
- "doctrine/mongodb-odm": "^2.2",
- "doctrine/mongodb-odm-bundle": "^4.0",
- "doctrine/orm": "^2.6.4",
- "elasticsearch/elasticsearch": "^7.11.0",
- "friends-of-behat/mink-browserkit-driver": "^1.3.1",
- "friends-of-behat/mink-extension": "^2.2",
- "friends-of-behat/symfony-extension": "^2.1",
- "guzzlehttp/guzzle": "^6.0 || ^7.0",
- "jangregor/phpstan-prophecy": "^1.0",
- "justinrainbow/json-schema": "^5.2.1",
- "phpdocumentor/reflection-docblock": "^3.0 || ^4.0 || ^5.1",
- "phpdocumentor/type-resolver": "^0.3 || ^0.4 || ^1.4",
- "phpspec/prophecy": "^1.10",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.1",
- "phpstan/phpstan-doctrine": "^1.0",
- "phpstan/phpstan-phpunit": "^1.0",
- "phpstan/phpstan-symfony": "^1.0",
- "psr/log": "^1.0 || ^2.0 || ^3.0",
- "ramsey/uuid": "^3.7 || ^4.0",
- "ramsey/uuid-doctrine": "^1.4",
- "soyuka/contexts": "dev-main",
- "soyuka/stubs-mongodb": "^1.0",
- "symfony/asset": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/browser-kit": "^4.4 || ^5.1 || ^6.0",
- "symfony/cache": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/config": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/console": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/css-selector": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/debug": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/dependency-injection": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/doctrine-bridge": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/dom-crawler": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/event-dispatcher": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/expression-language": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/finder": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/form": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/framework-bundle": "^4.4 || ^5.1 || ^6.0",
- "symfony/http-client": "^4.4 || ^5.1 || ^6.0",
- "symfony/intl": "^4.4 || ^5.3 || ^6.0",
- "symfony/maker-bundle": "^1.24",
- "symfony/mercure-bundle": "*",
- "symfony/messenger": "^4.4 || ^5.1 || ^6.0",
- "symfony/phpunit-bridge": "^5.4 || ^6.0",
- "symfony/routing": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/security-bundle": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/security-core": "^4.4 || ^5.1 || ^6.0",
- "symfony/twig-bundle": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/validator": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "symfony/web-profiler-bundle": "^4.4 || ^5.1 || ^6.0",
- "symfony/yaml": "^3.4 || ^4.4 || ^5.1 || ^6.0",
- "twig/twig": "^1.42.3 || ^2.12 || ^3.0",
- "webonyx/graphql-php": "^14.0"
- },
- "suggest": {
- "doctrine/mongodb-odm-bundle": "To support MongoDB. Only versions 4.0 and later are supported.",
- "elasticsearch/elasticsearch": "To support Elasticsearch.",
- "ocramius/package-versions": "To display the API Platform's version in the debug bar.",
- "phpdocumentor/reflection-docblock": "To support extracting metadata from PHPDoc.",
- "psr/cache-implementation": "To use metadata caching.",
- "ramsey/uuid": "To support Ramsey's UUID identifiers.",
- "symfony/cache": "To have metadata caching when using Symfony integration.",
- "symfony/config": "To load XML configuration files.",
- "symfony/expression-language": "To use authorization features.",
- "symfony/http-client": "To use the HTTP cache invalidation system.",
- "symfony/messenger": "To support messenger integration.",
- "symfony/security": "To use authorization features.",
- "symfony/twig-bundle": "To use the Swagger UI integration.",
- "symfony/uid": "To support Symfony UUID/ULID identifiers.",
- "symfony/web-profiler-bundle": "To use the data collector.",
- "webonyx/graphql-php": "To support GraphQL."
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.7.x-dev"
- },
- "symfony": {
- "require": "^3.4 || ^4.4 || ^5.1 || ^6.0"
- }
- },
- "autoload": {
- "files": [
- "src/deprecation.php"
- ],
- "psr-4": {
- "ApiPlatform\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Kévin Dunglas",
- "email": "kevin@dunglas.fr",
- "homepage": "https://dunglas.fr"
- }
- ],
- "description": "Build a fully-featured hypermedia or GraphQL API in minutes!",
- "homepage": "https://api-platform.com",
- "keywords": [
- "Hydra",
- "JSON-LD",
- "api",
- "graphql",
- "hal",
- "jsonapi",
- "openapi",
- "rest",
- "swagger"
- ],
- "support": {
- "issues": "https://github.com/api-platform/core/issues",
- "source": "https://github.com/api-platform/core/tree/v2.7.2"
- },
- "funding": [
- {
- "url": "https://tidelift.com/funding/github/packagist/api-platform/core",
- "type": "tidelift"
- }
- ],
- "time": "2022-10-07T09:12:23+00:00"
- },
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
@@ -3314,16 +3145,16 @@
},
{
"name": "symfony/cache",
- "version": "v6.1.5",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
- "reference": "9ae74e40fde37aba127ad5db65c5193f41f86f95"
+ "reference": "ee5d5b88162684a1377706f9c25125e97685ee61"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/cache/zipball/9ae74e40fde37aba127ad5db65c5193f41f86f95",
- "reference": "9ae74e40fde37aba127ad5db65c5193f41f86f95",
+ "url": "https://api.github.com/repos/symfony/cache/zipball/ee5d5b88162684a1377706f9c25125e97685ee61",
+ "reference": "ee5d5b88162684a1377706f9c25125e97685ee61",
"shasum": ""
},
"require": {
@@ -3390,7 +3221,7 @@
"psr6"
],
"support": {
- "source": "https://github.com/symfony/cache/tree/v6.1.5"
+ "source": "https://github.com/symfony/cache/tree/v6.1.7"
},
"funding": [
{
@@ -3406,7 +3237,7 @@
"type": "tidelift"
}
],
- "time": "2022-09-08T09:34:40+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -3566,16 +3397,16 @@
},
{
"name": "symfony/console",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "7fa3b9cf17363468795e539231a5c91b02b608fc"
+ "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/7fa3b9cf17363468795e539231a5c91b02b608fc",
- "reference": "7fa3b9cf17363468795e539231a5c91b02b608fc",
+ "url": "https://api.github.com/repos/symfony/console/zipball/a1282bd0c096e0bdb8800b104177e2ce404d8815",
+ "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815",
"shasum": ""
},
"require": {
@@ -3642,7 +3473,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v6.1.6"
+ "source": "https://github.com/symfony/console/tree/v6.1.7"
},
"funding": [
{
@@ -3658,7 +3489,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-26T21:42:49+00:00"
},
{
"name": "symfony/dependency-injection",
@@ -3816,20 +3647,20 @@
},
{
"name": "symfony/doctrine-bridge",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/doctrine-bridge.git",
- "reference": "5db7ac51c40d03d576b2696a6b55975e53a3dfd5"
+ "reference": "4b6b99d059333b9fec2d0abbe61ea38573319480"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/5db7ac51c40d03d576b2696a6b55975e53a3dfd5",
- "reference": "5db7ac51c40d03d576b2696a6b55975e53a3dfd5",
+ "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/4b6b99d059333b9fec2d0abbe61ea38573319480",
+ "reference": "4b6b99d059333b9fec2d0abbe61ea38573319480",
"shasum": ""
},
"require": {
- "doctrine/event-manager": "~1.0",
+ "doctrine/event-manager": "^1|^2",
"doctrine/persistence": "^2|^3",
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.1|^3",
@@ -3911,7 +3742,7 @@
"description": "Provides integration for Doctrine with various Symfony components",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/doctrine-bridge/tree/v6.1.6"
+ "source": "https://github.com/symfony/doctrine-bridge/tree/v6.1.7"
},
"funding": [
{
@@ -3927,7 +3758,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-10T09:34:31+00:00"
+ "time": "2022-10-15T06:26:03+00:00"
},
{
"name": "symfony/doctrine-messenger",
@@ -4076,16 +3907,16 @@
},
{
"name": "symfony/error-handler",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
- "reference": "49f718e41f1b6f0fd5730895ca5b1c37defd828d"
+ "reference": "699a26ce5ec656c198bf6e26398b0f0818c7e504"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/49f718e41f1b6f0fd5730895ca5b1c37defd828d",
- "reference": "49f718e41f1b6f0fd5730895ca5b1c37defd828d",
+ "url": "https://api.github.com/repos/symfony/error-handler/zipball/699a26ce5ec656c198bf6e26398b0f0818c7e504",
+ "reference": "699a26ce5ec656c198bf6e26398b0f0818c7e504",
"shasum": ""
},
"require": {
@@ -4127,7 +3958,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/error-handler/tree/v6.1.6"
+ "source": "https://github.com/symfony/error-handler/tree/v6.1.7"
},
"funding": [
{
@@ -4143,7 +3974,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -4564,16 +4395,16 @@
},
{
"name": "symfony/form",
- "version": "v6.1.5",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/form.git",
- "reference": "176a358d54c70ec70708c7cbb4e8ac93cc138e6c"
+ "reference": "6f5d13bb996dea03bbb5e43e1bbd90cbfdca1a83"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/form/zipball/176a358d54c70ec70708c7cbb4e8ac93cc138e6c",
- "reference": "176a358d54c70ec70708c7cbb4e8ac93cc138e6c",
+ "url": "https://api.github.com/repos/symfony/form/zipball/6f5d13bb996dea03bbb5e43e1bbd90cbfdca1a83",
+ "reference": "6f5d13bb996dea03bbb5e43e1bbd90cbfdca1a83",
"shasum": ""
},
"require": {
@@ -4646,7 +4477,7 @@
"description": "Allows to easily create, process and reuse HTML forms",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/form/tree/v6.1.5"
+ "source": "https://github.com/symfony/form/tree/v6.1.7"
},
"funding": [
{
@@ -4662,20 +4493,20 @@
"type": "tidelift"
}
],
- "time": "2022-09-09T09:34:27+00:00"
+ "time": "2022-10-23T10:33:34+00:00"
},
{
"name": "symfony/framework-bundle",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/framework-bundle.git",
- "reference": "b79e5866a8293de00c8436836c2038ec31916ee7"
+ "reference": "d402e86ce94bb3eb1ca3d6bb0393285c791e2b14"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/b79e5866a8293de00c8436836c2038ec31916ee7",
- "reference": "b79e5866a8293de00c8436836c2038ec31916ee7",
+ "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/d402e86ce94bb3eb1ca3d6bb0393285c791e2b14",
+ "reference": "d402e86ce94bb3eb1ca3d6bb0393285c791e2b14",
"shasum": ""
},
"require": {
@@ -4797,7 +4628,7 @@
"description": "Provides a tight integration between Symfony components and the Symfony full-stack framework",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/framework-bundle/tree/v6.1.6"
+ "source": "https://github.com/symfony/framework-bundle/tree/v6.1.7"
},
"funding": [
{
@@ -4813,20 +4644,20 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/http-client",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
- "reference": "c8c887f4813370550147afd27d9eb8a8523e53b2"
+ "reference": "f515d066728774efb34347a87580621416ca8968"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/c8c887f4813370550147afd27d9eb8a8523e53b2",
- "reference": "c8c887f4813370550147afd27d9eb8a8523e53b2",
+ "url": "https://api.github.com/repos/symfony/http-client/zipball/f515d066728774efb34347a87580621416ca8968",
+ "reference": "f515d066728774efb34347a87580621416ca8968",
"shasum": ""
},
"require": {
@@ -4881,7 +4712,7 @@
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-client/tree/v6.1.6"
+ "source": "https://github.com/symfony/http-client/tree/v6.1.7"
},
"funding": [
{
@@ -4897,7 +4728,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-12T05:10:31+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/http-client-contracts",
@@ -4982,16 +4813,16 @@
},
{
"name": "symfony/http-foundation",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "3ae8e9c57155fc48930493a629da293b32efbde0"
+ "reference": "792a1856d2b95273f0e1c3435785f1d01a60ecc6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3ae8e9c57155fc48930493a629da293b32efbde0",
- "reference": "3ae8e9c57155fc48930493a629da293b32efbde0",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/792a1856d2b95273f0e1c3435785f1d01a60ecc6",
+ "reference": "792a1856d2b95273f0e1c3435785f1d01a60ecc6",
"shasum": ""
},
"require": {
@@ -5037,7 +4868,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v6.1.6"
+ "source": "https://github.com/symfony/http-foundation/tree/v6.1.7"
},
"funding": [
{
@@ -5053,20 +4884,20 @@
"type": "tidelift"
}
],
- "time": "2022-10-02T08:30:52+00:00"
+ "time": "2022-10-12T09:44:59+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "102f99bf81799e93f61b9a73b2f38b309c587a94"
+ "reference": "8fc1ffe753948c47a103a809cdd6a4a8458b3254"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/102f99bf81799e93f61b9a73b2f38b309c587a94",
- "reference": "102f99bf81799e93f61b9a73b2f38b309c587a94",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8fc1ffe753948c47a103a809cdd6a4a8458b3254",
+ "reference": "8fc1ffe753948c47a103a809cdd6a4a8458b3254",
"shasum": ""
},
"require": {
@@ -5147,7 +4978,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v6.1.6"
+ "source": "https://github.com/symfony/http-kernel/tree/v6.1.7"
},
"funding": [
{
@@ -5163,20 +4994,20 @@
"type": "tidelift"
}
],
- "time": "2022-10-12T07:48:47+00:00"
+ "time": "2022-10-28T18:06:36+00:00"
},
{
"name": "symfony/intl",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/intl.git",
- "reference": "9ab546d9054b34feb2cb728349f6b8e8f18d4c43"
+ "reference": "8025e5b651512b21d3e768321d45a2e5e32e8c66"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/intl/zipball/9ab546d9054b34feb2cb728349f6b8e8f18d4c43",
- "reference": "9ab546d9054b34feb2cb728349f6b8e8f18d4c43",
+ "url": "https://api.github.com/repos/symfony/intl/zipball/8025e5b651512b21d3e768321d45a2e5e32e8c66",
+ "reference": "8025e5b651512b21d3e768321d45a2e5e32e8c66",
"shasum": ""
},
"require": {
@@ -5227,7 +5058,7 @@
"localization"
],
"support": {
- "source": "https://github.com/symfony/intl/tree/v6.1.6"
+ "source": "https://github.com/symfony/intl/tree/v6.1.7"
},
"funding": [
{
@@ -5243,20 +5074,20 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-23T10:33:34+00:00"
},
{
"name": "symfony/mailer",
- "version": "v6.1.5",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
- "reference": "e1b32deb9efc48def0c76b876860ad36f2123e89"
+ "reference": "7e19813c0b43387c55665780c4caea505cc48391"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mailer/zipball/e1b32deb9efc48def0c76b876860ad36f2123e89",
- "reference": "e1b32deb9efc48def0c76b876860ad36f2123e89",
+ "url": "https://api.github.com/repos/symfony/mailer/zipball/7e19813c0b43387c55665780c4caea505cc48391",
+ "reference": "7e19813c0b43387c55665780c4caea505cc48391",
"shasum": ""
},
"require": {
@@ -5301,7 +5132,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/mailer/tree/v6.1.5"
+ "source": "https://github.com/symfony/mailer/tree/v6.1.7"
},
"funding": [
{
@@ -5317,7 +5148,7 @@
"type": "tidelift"
}
],
- "time": "2022-08-29T06:58:39+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/messenger",
@@ -5407,16 +5238,16 @@
},
{
"name": "symfony/mime",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
- "reference": "5ae192b9a39730435cfec025a499f79d05ac68a3"
+ "reference": "f440f066d57691088d998d6e437ce98771144618"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/mime/zipball/5ae192b9a39730435cfec025a499f79d05ac68a3",
- "reference": "5ae192b9a39730435cfec025a499f79d05ac68a3",
+ "url": "https://api.github.com/repos/symfony/mime/zipball/f440f066d57691088d998d6e437ce98771144618",
+ "reference": "f440f066d57691088d998d6e437ce98771144618",
"shasum": ""
},
"require": {
@@ -5428,8 +5259,7 @@
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
- "symfony/mailer": "<5.4",
- "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6"
+ "symfony/mailer": "<5.4"
},
"require-dev": {
"egulias/email-validator": "^2.1.10|^3.1",
@@ -5437,7 +5267,7 @@
"symfony/dependency-injection": "^5.4|^6.0",
"symfony/property-access": "^5.4|^6.0",
"symfony/property-info": "^5.4|^6.0",
- "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6"
+ "symfony/serializer": "^5.2|^6.0"
},
"type": "library",
"autoload": {
@@ -5469,7 +5299,7 @@
"mime-type"
],
"support": {
- "source": "https://github.com/symfony/mime/tree/v6.1.6"
+ "source": "https://github.com/symfony/mime/tree/v6.1.7"
},
"funding": [
{
@@ -5485,7 +5315,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-19T08:10:53+00:00"
},
{
"name": "symfony/monolog-bridge",
@@ -6433,16 +6263,16 @@
},
{
"name": "symfony/property-access",
- "version": "v6.1.3",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-access.git",
- "reference": "25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5"
+ "reference": "cf034c0d8d25ed285bb8f6c2528ce6fac98563eb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/property-access/zipball/25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5",
- "reference": "25108ee9b62d6ef0815007d9c7cf6a7ba40bb7c5",
+ "url": "https://api.github.com/repos/symfony/property-access/zipball/cf034c0d8d25ed285bb8f6c2528ce6fac98563eb",
+ "reference": "cf034c0d8d25ed285bb8f6c2528ce6fac98563eb",
"shasum": ""
},
"require": {
@@ -6492,7 +6322,7 @@
"reflection"
],
"support": {
- "source": "https://github.com/symfony/property-access/tree/v6.1.3"
+ "source": "https://github.com/symfony/property-access/tree/v6.1.7"
},
"funding": [
{
@@ -6508,20 +6338,20 @@
"type": "tidelift"
}
],
- "time": "2022-06-27T17:24:16+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/property-info",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-info.git",
- "reference": "f28d0db9d2687f81d68d0dc6b2e42817647f5d64"
+ "reference": "b5a46ec66a4b77d4bd39d58c22710be888e55b68"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/property-info/zipball/f28d0db9d2687f81d68d0dc6b2e42817647f5d64",
- "reference": "f28d0db9d2687f81d68d0dc6b2e42817647f5d64",
+ "url": "https://api.github.com/repos/symfony/property-info/zipball/b5a46ec66a4b77d4bd39d58c22710be888e55b68",
+ "reference": "b5a46ec66a4b77d4bd39d58c22710be888e55b68",
"shasum": ""
},
"require": {
@@ -6581,7 +6411,7 @@
"validator"
],
"support": {
- "source": "https://github.com/symfony/property-info/tree/v6.1.6"
+ "source": "https://github.com/symfony/property-info/tree/v6.1.7"
},
"funding": [
{
@@ -6597,7 +6427,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-07T08:04:03+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/proxy-manager-bridge",
@@ -6667,16 +6497,16 @@
},
{
"name": "symfony/routing",
- "version": "v6.1.5",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "f8c1ebb43d0f39e5ecd12a732ba1952a3dd8455c"
+ "reference": "95effeb9d6e2cec861cee06bf5bbf82d09aea7f5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/f8c1ebb43d0f39e5ecd12a732ba1952a3dd8455c",
- "reference": "f8c1ebb43d0f39e5ecd12a732ba1952a3dd8455c",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/95effeb9d6e2cec861cee06bf5bbf82d09aea7f5",
+ "reference": "95effeb9d6e2cec861cee06bf5bbf82d09aea7f5",
"shasum": ""
},
"require": {
@@ -6735,7 +6565,7 @@
"url"
],
"support": {
- "source": "https://github.com/symfony/routing/tree/v6.1.5"
+ "source": "https://github.com/symfony/routing/tree/v6.1.7"
},
"funding": [
{
@@ -6751,7 +6581,7 @@
"type": "tidelift"
}
],
- "time": "2022-09-09T09:26:14+00:00"
+ "time": "2022-10-18T13:12:43+00:00"
},
{
"name": "symfony/runtime",
@@ -6931,16 +6761,16 @@
},
{
"name": "symfony/security-core",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/security-core.git",
- "reference": "e42fb611d1a36e6e1e34f8cd715cea108a39cad5"
+ "reference": "c84ff026d6fa3cf9cb54cca762f14b6a449fa557"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/security-core/zipball/e42fb611d1a36e6e1e34f8cd715cea108a39cad5",
- "reference": "e42fb611d1a36e6e1e34f8cd715cea108a39cad5",
+ "url": "https://api.github.com/repos/symfony/security-core/zipball/c84ff026d6fa3cf9cb54cca762f14b6a449fa557",
+ "reference": "c84ff026d6fa3cf9cb54cca762f14b6a449fa557",
"shasum": ""
},
"require": {
@@ -7002,7 +6832,7 @@
"description": "Symfony Security Component - Core Library",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/security-core/tree/v6.1.6"
+ "source": "https://github.com/symfony/security-core/tree/v6.1.7"
},
"funding": [
{
@@ -7018,7 +6848,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-02T08:30:52+00:00"
+ "time": "2022-10-23T10:33:34+00:00"
},
{
"name": "symfony/security-csrf",
@@ -7093,16 +6923,16 @@
},
{
"name": "symfony/security-http",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/security-http.git",
- "reference": "789492510f7127035da8bb5dbb4fb745970e2348"
+ "reference": "931b037cfd98e3f8c06a311e9c04abc9ee010ab9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/security-http/zipball/789492510f7127035da8bb5dbb4fb745970e2348",
- "reference": "789492510f7127035da8bb5dbb4fb745970e2348",
+ "url": "https://api.github.com/repos/symfony/security-http/zipball/931b037cfd98e3f8c06a311e9c04abc9ee010ab9",
+ "reference": "931b037cfd98e3f8c06a311e9c04abc9ee010ab9",
"shasum": ""
},
"require": {
@@ -7156,7 +6986,7 @@
"description": "Symfony Security Component - HTTP Integration",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/security-http/tree/v6.1.6"
+ "source": "https://github.com/symfony/security-http/tree/v6.1.7"
},
"funding": [
{
@@ -7172,7 +7002,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-01T16:55:12+00:00"
+ "time": "2022-10-23T10:33:34+00:00"
},
{
"name": "symfony/serializer",
@@ -7424,16 +7254,16 @@
},
{
"name": "symfony/string",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "7e7e0ff180d4c5a6636eaad57b65092014b61864"
+ "reference": "823f143370880efcbdfa2dbca946b3358c4707e5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/7e7e0ff180d4c5a6636eaad57b65092014b61864",
- "reference": "7e7e0ff180d4c5a6636eaad57b65092014b61864",
+ "url": "https://api.github.com/repos/symfony/string/zipball/823f143370880efcbdfa2dbca946b3358c4707e5",
+ "reference": "823f143370880efcbdfa2dbca946b3358c4707e5",
"shasum": ""
},
"require": {
@@ -7489,7 +7319,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v6.1.6"
+ "source": "https://github.com/symfony/string/tree/v6.1.7"
},
"funding": [
{
@@ -7754,16 +7584,16 @@
},
{
"name": "symfony/twig-bridge",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/twig-bridge.git",
- "reference": "368e9bac2dbaed85d943745b521077f8101b599d"
+ "reference": "10f4ccba086ca81bbac9ee5e065d9f99565b3983"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/368e9bac2dbaed85d943745b521077f8101b599d",
- "reference": "368e9bac2dbaed85d943745b521077f8101b599d",
+ "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/10f4ccba086ca81bbac9ee5e065d9f99565b3983",
+ "reference": "10f4ccba086ca81bbac9ee5e065d9f99565b3983",
"shasum": ""
},
"require": {
@@ -7856,7 +7686,7 @@
"description": "Provides integration for Twig with various Symfony components",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/twig-bridge/tree/v6.1.6"
+ "source": "https://github.com/symfony/twig-bridge/tree/v6.1.7"
},
"funding": [
{
@@ -7872,7 +7702,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-12T05:10:31+00:00"
+ "time": "2022-10-19T08:10:53+00:00"
},
{
"name": "symfony/twig-bundle",
@@ -8036,16 +7866,16 @@
},
{
"name": "symfony/validator",
- "version": "v6.1.6",
+ "version": "v6.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/validator.git",
- "reference": "e5589882403e1e19774d7c5ffb65d9c6466d216c"
+ "reference": "0cc147f2e4a0d78221db85545751cd8764bbc156"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/validator/zipball/e5589882403e1e19774d7c5ffb65d9c6466d216c",
- "reference": "e5589882403e1e19774d7c5ffb65d9c6466d216c",
+ "url": "https://api.github.com/repos/symfony/validator/zipball/0cc147f2e4a0d78221db85545751cd8764bbc156",
+ "reference": "0cc147f2e4a0d78221db85545751cd8764bbc156",
"shasum": ""
},
"require": {
@@ -8124,7 +7954,7 @@
"description": "Provides tools to validate values",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/validator/tree/v6.1.6"
+ "source": "https://github.com/symfony/validator/tree/v6.1.7"
},
"funding": [
{
@@ -8140,7 +7970,7 @@
"type": "tidelift"
}
],
- "time": "2022-10-02T08:30:52+00:00"
+ "time": "2022-10-28T16:23:08+00:00"
},
{
"name": "symfony/var-dumper",
@@ -8575,6 +8405,182 @@
],
"time": "2022-10-07T08:04:03+00:00"
},
+ {
+ "name": "symfonycasts/reset-password-bundle",
+ "version": "v1.16.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/SymfonyCasts/reset-password-bundle.git",
+ "reference": "05216bfd80d4019a155d326501f00bf92b9cd439"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/SymfonyCasts/reset-password-bundle/zipball/05216bfd80d4019a155d326501f00bf92b9cd439",
+ "reference": "05216bfd80d4019a155d326501f00bf92b9cd439",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": ">=7.2.5",
+ "symfony/config": "^5.4 | ^6.0",
+ "symfony/dependency-injection": "^5.4 | ^6.0",
+ "symfony/deprecation-contracts": "^2.2 | ^3.0",
+ "symfony/http-kernel": "^5.4 | ^6.0"
+ },
+ "conflict": {
+ "doctrine/orm": "<2.7",
+ "php": ">=8.1 <8.1.10"
+ },
+ "require-dev": {
+ "doctrine/doctrine-bundle": "^2.0.3",
+ "doctrine/orm": "^2.7",
+ "symfony/framework-bundle": "^5.4 | ^6.0",
+ "symfony/phpunit-bridge": "^5.4 | ^6.0",
+ "vimeo/psalm": "^4.3"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "SymfonyCasts\\Bundle\\ResetPassword\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Symfony bundle that adds password reset functionality.",
+ "support": {
+ "issues": "https://github.com/SymfonyCasts/reset-password-bundle/issues",
+ "source": "https://github.com/SymfonyCasts/reset-password-bundle/tree/v1.16.0"
+ },
+ "time": "2022-10-04T08:38:58+00:00"
+ },
+ {
+ "name": "symfonycasts/verify-email-bundle",
+ "version": "v1.12.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/SymfonyCasts/verify-email-bundle.git",
+ "reference": "c60349bf5a6f5e9a40bd88ec7d19b9ffd7f6af12"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/SymfonyCasts/verify-email-bundle/zipball/c60349bf5a6f5e9a40bd88ec7d19b9ffd7f6af12",
+ "reference": "c60349bf5a6f5e9a40bd88ec7d19b9ffd7f6af12",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": ">=7.2.5",
+ "symfony/config": "^5.4 | ^6.0",
+ "symfony/dependency-injection": "^5.4 | ^6.0",
+ "symfony/deprecation-contracts": "^2.2 | ^3.0",
+ "symfony/http-kernel": "^5.4 | ^6.0",
+ "symfony/routing": "^5.4 | ^6.0"
+ },
+ "require-dev": {
+ "doctrine/orm": "^2.7",
+ "doctrine/persistence": "^2.0",
+ "symfony/framework-bundle": "^5.4 | ^6.0",
+ "symfony/phpunit-bridge": "^5.4 | ^6.0",
+ "vimeo/psalm": "^4.3"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "SymfonyCasts\\Bundle\\VerifyEmail\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Simple, stylish Email Verification for Symfony",
+ "support": {
+ "issues": "https://github.com/SymfonyCasts/verify-email-bundle/issues",
+ "source": "https://github.com/SymfonyCasts/verify-email-bundle/tree/v1.12.0"
+ },
+ "time": "2022-10-04T08:35:54+00:00"
+ },
+ {
+ "name": "twig/extra-bundle",
+ "version": "v3.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/twig-extra-bundle.git",
+ "reference": "2e58256b0e9fe52f30149347c0547e4633304765"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/2e58256b0e9fe52f30149347c0547e4633304765",
+ "reference": "2e58256b0e9fe52f30149347c0547e4633304765",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/framework-bundle": "^4.4|^5.0|^6.0",
+ "symfony/twig-bundle": "^4.4|^5.0|^6.0",
+ "twig/twig": "^2.7|^3.0"
+ },
+ "require-dev": {
+ "league/commonmark": "^1.0|^2.0",
+ "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0",
+ "twig/cache-extra": "^3.0",
+ "twig/cssinliner-extra": "^2.12|^3.0",
+ "twig/html-extra": "^2.12|^3.0",
+ "twig/inky-extra": "^2.12|^3.0",
+ "twig/intl-extra": "^2.12|^3.0",
+ "twig/markdown-extra": "^2.12|^3.0",
+ "twig/string-extra": "^2.12|^3.0"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Twig\\Extra\\TwigExtraBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ }
+ ],
+ "description": "A Symfony bundle for extra Twig extensions",
+ "homepage": "https://twig.symfony.com",
+ "keywords": [
+ "bundle",
+ "extra",
+ "twig"
+ ],
+ "support": {
+ "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-01-04T13:58:53+00:00"
+ },
{
"name": "twig/markdown-extra",
"version": "v3.4.0",
@@ -8650,16 +8656,16 @@
},
{
"name": "twig/twig",
- "version": "v3.3.10",
+ "version": "v3.4.3",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "8442df056c51b706793adf80a9fd363406dd3674"
+ "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/8442df056c51b706793adf80a9fd363406dd3674",
- "reference": "8442df056c51b706793adf80a9fd363406dd3674",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58",
+ "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58",
"shasum": ""
},
"require": {
@@ -8674,7 +8680,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.3-dev"
+ "dev-master": "3.4-dev"
}
},
"autoload": {
@@ -8710,7 +8716,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
- "source": "https://github.com/twigphp/Twig/tree/v3.3.10"
+ "source": "https://github.com/twigphp/Twig/tree/v3.4.3"
},
"funding": [
{
@@ -8722,7 +8728,7 @@
"type": "tidelift"
}
],
- "time": "2022-04-06T06:47:41+00:00"
+ "time": "2022-09-28T08:42:51+00:00"
},
{
"name": "webmozart/assert",
@@ -8781,62 +8787,6 @@
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
},
"time": "2022-06-03T18:03:27+00:00"
- },
- {
- "name": "willdurand/negotiation",
- "version": "3.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/willdurand/Negotiation.git",
- "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
- "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1.0"
- },
- "require-dev": {
- "symfony/phpunit-bridge": "^5.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.0-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Negotiation\\": "src/Negotiation"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "William Durand",
- "email": "will+git@drnd.me"
- }
- ],
- "description": "Content Negotiation tools for PHP provided as a standalone library.",
- "homepage": "http://williamdurand.fr/Negotiation/",
- "keywords": [
- "accept",
- "content",
- "format",
- "header",
- "negotiation"
- ],
- "support": {
- "issues": "https://github.com/willdurand/Negotiation/issues",
- "source": "https://github.com/willdurand/Negotiation/tree/3.1.0"
- },
- "time": "2022-01-30T20:08:53+00:00"
}
],
"packages-dev": [
diff --git a/config/bundles.php b/config/bundles.php
index 9cdd77e..dd71193 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -15,7 +15,7 @@ return [
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
Knp\Bundle\TimeBundle\KnpTimeBundle::class => ['all' => true],
- FOS\CKEditorBundle\FOSCKEditorBundle::class => ['all' => true],
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
- ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
+ SymfonyCasts\Bundle\VerifyEmail\SymfonyCastsVerifyEmailBundle::class => ['all' => true],
+ SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true],
];
diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
deleted file mode 100644
index 9c98d4c..0000000
--- a/config/packages/api_platform.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-api_platform:
- mapping:
- paths: ['%kernel.project_dir%/src/Entity']
- patch_formats:
- json: ['application/merge-patch+json']
- swagger:
- versions: [3]
- show_webby: false
\ No newline at end of file
diff --git a/config/packages/fos_ckeditor.yaml b/config/packages/fos_ckeditor.yaml
deleted file mode 100644
index ced8b0b..0000000
--- a/config/packages/fos_ckeditor.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-# Read the documentation: https://symfony.com/doc/current/bundles/FOSCKEditorBundle/index.html
-
-twig:
- form_themes:
- - '@FOSCKEditor/Form/ckeditor_widget.html.twig'
diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml
index 7853e9e..9ef7c1f 100644
--- a/config/packages/framework.yaml
+++ b/config/packages/framework.yaml
@@ -1,7 +1,7 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
- #csrf_protection: true
+ csrf_protection: true
http_method_override: false
# Enables session support. Note that the session will ONLY be started if you read or write from it.
diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml
index 62feb28..0285d4f 100644
--- a/config/packages/messenger.yaml
+++ b/config/packages/messenger.yaml
@@ -16,7 +16,7 @@ framework:
# sync: 'sync://'
routing:
- Symfony\Component\Mailer\Messenger\SendEmailMessage: async
+ #Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Symfony\Component\Notifier\Message\ChatMessage: async
Symfony\Component\Notifier\Message\SmsMessage: async
diff --git a/config/packages/reset_password.yaml b/config/packages/reset_password.yaml
new file mode 100644
index 0000000..4fa1d37
--- /dev/null
+++ b/config/packages/reset_password.yaml
@@ -0,0 +1,4 @@
+symfonycasts_reset_password:
+ request_password_repository: App\Repository\ResetPasswordRequestRepository
+ lifetime: 3600
+ throttle_limit: 1
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 45ff287..6d998f7 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -22,13 +22,11 @@ security:
main:
lazy: true
provider: app_user_provider
- # custom_authenticator: App\Security\LoginFormAuthenticator
-
- json_login:
- check_path: app_login
- username_path: username
- password_path: password
+ custom_authenticator: App\Security\LoginFormAuthenticator
+ ##form_login:
+ # login_path: app_login
+ # check_path: app_login
logout:
path: app_logout
switch_user: true
diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml
index 8356000..a963e03 100644
--- a/config/packages/twig.yaml
+++ b/config/packages/twig.yaml
@@ -1,7 +1,10 @@
twig:
- default_path: '%kernel.project_dir%/templates'
+# default_path: '%kernel.project_dir%/templates'
+ paths:
+ '%kernel.project_dir%/templates/themes/default': default
+ '%kernel.project_dir%/templates/admin': admin
form_themes:
- - '@FOSCKEditor/Form/ckeditor_widget.html.twig'
+ - bootstrap_5_layout.html.twig
when@test:
twig:
diff --git a/config/routes/api_platform.yaml b/config/routes/api_platform.yaml
deleted file mode 100644
index 38f11cb..0000000
--- a/config/routes/api_platform.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-api_platform:
- resource: .
- type: api_platform
- prefix: /api
diff --git a/migrations/Version20220409135404.php b/migrations/Version20220409135404.php
deleted file mode 100644
index 962733d..0000000
--- a/migrations/Version20220409135404.php
+++ /dev/null
@@ -1,31 +0,0 @@
-addSql('ALTER TABLE user ADD first_name VARCHAR(255) DEFAULT NULL, ADD last_name 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 first_name, DROP last_name');
- }
-}
diff --git a/migrations/Version20220409150258.php b/migrations/Version20220409150258.php
deleted file mode 100644
index 8566eea..0000000
--- a/migrations/Version20220409150258.php
+++ /dev/null
@@ -1,31 +0,0 @@
-addSql('CREATE TABLE quotes (id INT AUTO_INCREMENT NOT NULL, quote LONGTEXT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
- }
-
- public function down(Schema $schema): void
- {
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('DROP TABLE quotes');
- }
-}
diff --git a/migrations/Version20220410123550.php b/migrations/Version20220410123550.php
deleted file mode 100644
index ebbd88c..0000000
--- a/migrations/Version20220410123550.php
+++ /dev/null
@@ -1,33 +0,0 @@
-addSql('CREATE TABLE projects (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, url VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
- $this->addSql('ALTER TABLE user CHANGE first_name first_name VARCHAR(255) DEFAULT NULL');
- }
-
- public function down(Schema $schema): void
- {
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('DROP TABLE projects');
- $this->addSql('ALTER TABLE `user` CHANGE first_name first_name VARCHAR(255) DEFAULT \'\'');
- }
-}
diff --git a/migrations/Version20220410131552.php b/migrations/Version20220410131552.php
deleted file mode 100644
index 9037710..0000000
--- a/migrations/Version20220410131552.php
+++ /dev/null
@@ -1,35 +0,0 @@
-addSql('CREATE TABLE projects_user (projects_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_B38D6A811EDE0F55 (projects_id), INDEX IDX_B38D6A81A76ED395 (user_id), PRIMARY KEY(projects_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
- $this->addSql('ALTER TABLE projects_user ADD CONSTRAINT FK_B38D6A811EDE0F55 FOREIGN KEY (projects_id) REFERENCES projects (id) ON DELETE CASCADE');
- $this->addSql('ALTER TABLE projects_user ADD CONSTRAINT FK_B38D6A81A76ED395 FOREIGN KEY (user_id) REFERENCES `user` (id) ON DELETE CASCADE');
- $this->addSql('ALTER TABLE projects ADD teaser_image VARCHAR(255) DEFAULT NULL');
- }
-
- public function down(Schema $schema): void
- {
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('DROP TABLE projects_user');
- $this->addSql('ALTER TABLE projects DROP teaser_image');
- }
-}
diff --git a/migrations/Version20220412144008.php b/migrations/Version20220412144008.php
deleted file mode 100644
index ca7e7ec..0000000
--- a/migrations/Version20220412144008.php
+++ /dev/null
@@ -1,31 +0,0 @@
-addSql('ALTER TABLE user ADD avatar 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 avatar');
- }
-}
diff --git a/migrations/Version20220423085724.php b/migrations/Version20220423085724.php
deleted file mode 100644
index aebb338..0000000
--- a/migrations/Version20220423085724.php
+++ /dev/null
@@ -1,32 +0,0 @@
-addSql('CREATE TABLE pages (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, name VARCHAR(255) NOT NULL, content LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', modified_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_2074E5757E3C61F9 (owner_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
- $this->addSql('ALTER TABLE pages ADD CONSTRAINT FK_2074E5757E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)');
- }
-
- public function down(Schema $schema): void
- {
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('DROP TABLE pages');
- }
-}
diff --git a/migrations/Version20220425082917.php b/migrations/Version20220425082917.php
deleted file mode 100644
index 5b80952..0000000
--- a/migrations/Version20220425082917.php
+++ /dev/null
@@ -1,31 +0,0 @@
-addSql('ALTER TABLE user ADD created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', ADD modified_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\'');
- }
-
- public function down(Schema $schema): void
- {
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('ALTER TABLE `user` DROP created_at, DROP modified_at');
- }
-}
diff --git a/migrations/Version20221028172857.php b/migrations/Version20221028172857.php
new file mode 100644
index 0000000..6bf5bea
--- /dev/null
+++ b/migrations/Version20221028172857.php
@@ -0,0 +1,73 @@
+addSql('CREATE TABLE pages (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, name VARCHAR(255) NOT NULL, content LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', modified_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', slug VARCHAR(255) NOT NULL, INDEX IDX_2074E5757E3C61F9 (owner_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE projects (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255) NOT NULL, url VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', teaser_image VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE projects_user (projects_id INT NOT NULL, user_id INT NOT NULL, INDEX IDX_B38D6A811EDE0F55 (projects_id), INDEX IDX_B38D6A81A76ED395 (user_id), PRIMARY KEY(projects_id, user_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE quotes (id INT AUTO_INCREMENT NOT NULL, quote LONGTEXT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL, available_at DATETIME NOT NULL, delivered_at DATETIME DEFAULT NULL, INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('ALTER TABLE pages ADD CONSTRAINT FK_2074E5757E3C61F9 FOREIGN KEY (owner_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE projects_user ADD CONSTRAINT FK_B38D6A811EDE0F55 FOREIGN KEY (projects_id) REFERENCES projects (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE projects_user ADD CONSTRAINT FK_B38D6A81A76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
+ $this->addSql('ALTER TABLE blog DROP FOREIGN KEY FK_C0155143DD7B2EBC');
+ $this->addSql('ALTER TABLE blog DROP FOREIGN KEY FK_C0155143F675F31B');
+ $this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526CDAE07E97');
+ $this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526CDD7B2EBC');
+ $this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526CF675F31B');
+ $this->addSql('ALTER TABLE blog_section DROP FOREIGN KEY FK_C185C76CD823E37A');
+ $this->addSql('ALTER TABLE blog_section DROP FOREIGN KEY FK_C185C76CDAE07E97');
+ $this->addSql('DROP TABLE reset_password_request');
+ $this->addSql('DROP TABLE blog');
+ $this->addSql('DROP TABLE comment');
+ $this->addSql('DROP TABLE blog_section');
+ $this->addSql('DROP TABLE section');
+ $this->addSql('ALTER TABLE user ADD first_name VARCHAR(255) DEFAULT NULL, ADD last_name VARCHAR(255) DEFAULT NULL, ADD modified_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', DROP last_login_at, CHANGE created_at created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\'');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('CREATE TABLE reset_password_request (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, selector VARCHAR(20) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, hashed_token VARCHAR(100) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, requested_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', expires_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_7CE748AA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
+ $this->addSql('CREATE TABLE blog (id INT AUTO_INCREMENT NOT NULL, author_id INT NOT NULL, edited_by_id INT DEFAULT NULL, title VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, teaser LONGTEXT CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, teaser_image VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, content LONGTEXT CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, created_at DATETIME NOT NULL, edited_at DATETIME DEFAULT NULL, edit_reason VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, slug VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, INDEX IDX_C0155143DD7B2EBC (edited_by_id), UNIQUE INDEX UNIQ_C0155143989D9B62 (slug), INDEX IDX_C0155143F675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
+ $this->addSql('CREATE TABLE comment (id INT AUTO_INCREMENT NOT NULL, blog_id INT NOT NULL, author_id INT NOT NULL, edited_by_id INT DEFAULT NULL, title VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, content LONGTEXT CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, created_at DATETIME NOT NULL, edited_at DATETIME DEFAULT NULL, edit_reason VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, INDEX IDX_9474526CDD7B2EBC (edited_by_id), INDEX IDX_9474526CDAE07E97 (blog_id), INDEX IDX_9474526CF675F31B (author_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
+ $this->addSql('CREATE TABLE blog_section (blog_id INT NOT NULL, section_id INT NOT NULL, INDEX IDX_C185C76CDAE07E97 (blog_id), INDEX IDX_C185C76CD823E37A (section_id), PRIMARY KEY(blog_id, section_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
+ $this->addSql('CREATE TABLE section (id INT AUTO_INCREMENT NOT NULL, title VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, description VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, teaser_image VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
+ $this->addSql('ALTER TABLE reset_password_request ADD CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE blog ADD CONSTRAINT FK_C0155143DD7B2EBC FOREIGN KEY (edited_by_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE blog ADD CONSTRAINT FK_C0155143F675F31B FOREIGN KEY (author_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526CDAE07E97 FOREIGN KEY (blog_id) REFERENCES blog (id)');
+ $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526CDD7B2EBC FOREIGN KEY (edited_by_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526CF675F31B FOREIGN KEY (author_id) REFERENCES user (id)');
+ $this->addSql('ALTER TABLE blog_section ADD CONSTRAINT FK_C185C76CD823E37A FOREIGN KEY (section_id) REFERENCES section (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE blog_section ADD CONSTRAINT FK_C185C76CDAE07E97 FOREIGN KEY (blog_id) REFERENCES blog (id) ON DELETE CASCADE');
+ $this->addSql('ALTER TABLE pages DROP FOREIGN KEY FK_2074E5757E3C61F9');
+ $this->addSql('ALTER TABLE projects_user DROP FOREIGN KEY FK_B38D6A811EDE0F55');
+ $this->addSql('ALTER TABLE projects_user DROP FOREIGN KEY FK_B38D6A81A76ED395');
+ $this->addSql('DROP TABLE pages');
+ $this->addSql('DROP TABLE projects');
+ $this->addSql('DROP TABLE projects_user');
+ $this->addSql('DROP TABLE quotes');
+ $this->addSql('DROP TABLE messenger_messages');
+ $this->addSql('ALTER TABLE user ADD last_login_at DATETIME DEFAULT NULL, DROP first_name, DROP last_name, DROP modified_at, CHANGE created_at created_at DATETIME NOT NULL');
+ }
+}
diff --git a/migrations/Version20220424100610.php b/migrations/Version20221030105205.php
similarity index 69%
rename from migrations/Version20220424100610.php
rename to migrations/Version20221030105205.php
index b3d9fe4..68dfacb 100644
--- a/migrations/Version20220424100610.php
+++ b/migrations/Version20221030105205.php
@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
-final class Version20220424100610 extends AbstractMigration
+final class Version20221030105205 extends AbstractMigration
{
public function getDescription(): string
{
@@ -20,12 +20,12 @@ final class Version20220424100610 extends AbstractMigration
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
- $this->addSql('ALTER TABLE pages ADD slug VARCHAR(255) NOT NULL');
+ $this->addSql('ALTER TABLE user ADD agreed_terms_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\'');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
- $this->addSql('ALTER TABLE pages DROP slug');
+ $this->addSql('ALTER TABLE user DROP agreed_terms_at');
}
}
diff --git a/migrations/Version20221030161847.php b/migrations/Version20221030161847.php
new file mode 100644
index 0000000..95cd404
--- /dev/null
+++ b/migrations/Version20221030161847.php
@@ -0,0 +1,33 @@
+addSql('CREATE TABLE reset_password_request (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, selector VARCHAR(20) NOT NULL, hashed_token VARCHAR(100) NOT NULL, requested_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', expires_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_7CE748AA76ED395 (user_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
+ $this->addSql('ALTER TABLE reset_password_request ADD CONSTRAINT FK_7CE748AA76ED395 FOREIGN KEY (user_id) REFERENCES user (id)');
+ }
+
+ public function down(Schema $schema): void
+ {
+ // this down() migration is auto-generated, please modify it to your needs
+ $this->addSql('ALTER TABLE reset_password_request DROP FOREIGN KEY FK_7CE748AA76ED395');
+ $this->addSql('DROP TABLE reset_password_request');
+ }
+}
diff --git a/src/Controller/BaseController.php b/src/Controller/BaseController.php
new file mode 100644
index 0000000..b28e675
--- /dev/null
+++ b/src/Controller/BaseController.php
@@ -0,0 +1,16 @@
+getUser();
+ $quote = $quotesRepository->findOneRandom();
+
+ return $this->render(view: '@default/base.html.twig', parameters: [
+ 'user' => $user,
+ 'quote' => json_encode(value: $quote->getQuote())
+ ]);
+ }
/**
* @throws Exception
*/
- #[Route(path: '/', name: 'app_main')]
- public function quote(SerializerInterface $serializer, QuotesRepository $quotesRepository): Response
+ #[Route(path: '/logout', name: 'app_logout')]
+ public function logout(): never
{
- $quote = $quotesRepository->findOneRandom();
-
- return $this->render(view: self::TEMPLATE_DIR . 'base.html.twig', parameters: [
- 'template_dir' => self::TEMPLATE_DIR,
- 'user' => $serializer->serialize(data: $this->getUser(), format: 'jsonld'),
- 'quote' => json_encode(value: $quote->getQuote())
- ]);
+ throw new Exception(message: 'Logout should never be reached.');
}
}
diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php
index 80bb9f5..6638c81 100644
--- a/src/Controller/PagesController.php
+++ b/src/Controller/PagesController.php
@@ -10,8 +10,6 @@ use Symfony\Component\Routing\Annotation\Route;
class PagesController extends AbstractController
{
- const TEMPLATE_DIR = 'themes/default/';
-
#[Route(path: '/pages/{name}', name: 'pages_display')]
public function display(PagesRepository $pagesRepository, string $name): Response
{
@@ -25,7 +23,7 @@ class PagesController extends AbstractController
$page->setContent(content: 'The requested page was not found.');
}
- return $this->render(view: 'pages/display.html.twig', parameters: [
+ return $this->render(view: '@default/pages/display.html.twig', parameters: [
'page' => $page,
]);
}
@@ -33,18 +31,12 @@ class PagesController extends AbstractController
#[Route(path: '/imprint', name: 'app_imprint')]
public function imprint(): Response
{
- return $this->render(view: self::TEMPLATE_DIR . 'pages/imprint.html.twig', parameters: [
- 'template_dir' => self::TEMPLATE_DIR,
- 'controller_name' => 'PagesController',
- ]);
+ return $this->render(view: '@default/pages/imprint.html.twig');
}
#[Route(path: '/privacy', name: 'app_privacy')]
public function privacy(): Response
{
- return $this->render(view: self::TEMPLATE_DIR . 'pages/privacy.html.twig', parameters: [
- 'template_dir' => self::TEMPLATE_DIR,
- 'controller_name' => 'PagesController',
- ]);
+ return $this->render(view: '@default/pages/privacy.html.twig');
}
}
diff --git a/src/Controller/ProjectsController.php b/src/Controller/ProjectsController.php
index d236b43..fb8470c 100644
--- a/src/Controller/ProjectsController.php
+++ b/src/Controller/ProjectsController.php
@@ -13,7 +13,7 @@ class ProjectsController extends AbstractController
public function index(ProjectsRepository $projectsRepository, string $name = ''): Response
{
if ($name == '') {
- return $this->render(view: 'projects/index.html.twig', parameters: [
+ return $this->render(view: '@default/projects/index.html.twig', parameters: [
'projects' => $projectsRepository->findAll(),
]);
} else {
@@ -22,7 +22,7 @@ class ProjectsController extends AbstractController
// $parsedReadMe = $markdownParser->transformMarkdown(text: $readMe);
- return $this->render(view: 'projects/show.html.twig', parameters: [
+ return $this->render(view: '@default/projects/show.html.twig', parameters: [
'project' => $project,
'readme' => $readMe,
]);
diff --git a/src/Controller/ResetPasswordController.php b/src/Controller/ResetPasswordController.php
new file mode 100644
index 0000000..ad27e80
--- /dev/null
+++ b/src/Controller/ResetPasswordController.php
@@ -0,0 +1,179 @@
+createForm(type: ResetPasswordRequestFormType::class);
+ $form->handleRequest(request: $request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ return $this->processSendingPasswordResetEmail(
+ formData: $form->get(name: 'account')->getData(),
+ mailer: $mailer
+ );
+ }
+
+ return $this->render(view: '@default/security/forgot_password.html.twig', parameters: [
+ 'requestForm' => $form->createView(),
+ ]);
+ }
+
+ /**
+ * Confirmation page after a user has requested a password reset.
+ */
+ #[Route(path: '/security/recovery/mail/sent', name: 'security_recovery_mail_sent')]
+ public function checkEmail(): Response
+ {
+ // Generate a fake token if the user does not exist or someone hit this page directly.
+ // This prevents exposing whether a user was found with the given email address or username or not
+ if (null === ($resetToken = $this->getTokenObjectFromSession())) {
+ $resetToken = $this->resetPasswordHelper->generateFakeResetToken();
+ }
+
+ return $this->render(view: '@default/security/recovery_mail_sent.html.twig', parameters: [
+ 'resetToken' => $resetToken,
+ ]);
+ }
+
+ /**
+ * Validates and process the reset URL that the user clicked in their email.
+ */
+ #[Route(path: '/security/recovery/reset/{token}', name: 'security_recovery_reset')]
+ public function reset(Request $request, UserPasswordHasherInterface $passwordHasher, TranslatorInterface $translator, 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: $token);
+
+ return $this->redirectToRoute(route: 'security_recovery_reset');
+ }
+
+ $token = $this->getTokenFromSession();
+ if (null === $token) {
+ throw $this->createNotFoundException(message: 'No reset password token found in the URL or in the session.');
+ }
+
+ try {
+ $user = $this->resetPasswordHelper->validateTokenAndFetchUser(fullToken: $token);
+ } catch (ResetPasswordExceptionInterface $e) {
+ $this->addFlash(type: 'reset_password_error', message: sprintf(
+ '%s - %s',
+ $translator->trans(id: ResetPasswordExceptionInterface::MESSAGE_PROBLEM_VALIDATE, parameters: [], domain: 'ResetPasswordBundle'),
+ $translator->trans(id: $e->getReason(), parameters: [], domain: 'ResetPasswordBundle')
+ ));
+
+ return $this->redirectToRoute(route: 'app_forgot_password_request');
+ }
+
+ // The token is valid; allow the user to change their password.
+ $form = $this->createForm(type: ChangePasswordFormType::class);
+ $form->handleRequest(request: $request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ // A password reset token should be used only once, remove it.
+ $this->resetPasswordHelper->removeResetRequest(fullToken: $token);
+
+ // Encode(hash) the plain password, and set it.
+ $encodedPassword = $passwordHasher->hashPassword(
+ user: $user,
+ plainPassword: $form->get(name: 'plainPassword')->getData()
+ );
+
+ $user->setPassword($encodedPassword);
+ $this->entityManager->flush();
+
+ // The session is cleaned up after the password has been changed.
+ $this->cleanSessionAfterReset();
+
+ $this->addFlash(type: 'success', message: 'Your password has been changed.');
+
+ return $this->redirectToRoute(route: 'app_main');
+ }
+
+ return $this->render(view: '@default/security/reset_password.html.twig', parameters: [
+ 'resetForm' => $form->createView(),
+ ]);
+ }
+
+ private function processSendingPasswordResetEmail(string $formData, MailerInterface $mailer): RedirectResponse
+ {
+ $user = $this->entityManager->getRepository(entityName: User::class)->findOneBy(criteria: [
+ 'email' => $formData,
+ ]);
+
+ if (!$user) {
+ $user = $this->entityManager->getRepository(entityName: User::class)->findOneBy(criteria: [
+ 'username' => $formData,
+ ]);
+ }
+
+ // Do not reveal whether a user account was found or not.
+// if (!$user) {
+// return $this->redirectToRoute(route: 'app_check_email');
+// }
+
+ try {
+ $resetToken = $this->resetPasswordHelper->generateResetToken(user: $user);
+ } catch (ResetPasswordExceptionInterface $e) {
+ $this->addFlash(type: 'reset_password_error', message: sprintf(
+ '%s - %s',
+ ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE,
+ $e->getReason()
+ ));
+
+ return $this->redirectToRoute(route: 'security_forgot_password');
+ }
+
+ $email = (new TemplatedEmail())
+ ->from(new Address(address: 'tracer@24unix.net', name: '24unix.net'))
+ ->to($user->getEmail())
+ ->subject(subject: 'Your password reset request')
+ ->htmlTemplate(template: '@default/security/mail/recovery.html.twig')
+ ->context(context: [
+ 'resetToken' => $resetToken,
+ ]);
+
+ $mailer->send(message: $email);
+
+ // Store the token object in session for retrieval in check-email route.
+ $this->setTokenObjectInSession(token: $resetToken);
+
+ return $this->redirectToRoute(route: 'security_recovery_mail_sent');
+ }
+}
diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php
index a4f38f6..3391c39 100644
--- a/src/Controller/SecurityController.php
+++ b/src/Controller/SecurityController.php
@@ -2,46 +2,117 @@
namespace App\Controller;
-use ApiPlatform\Core\Api\IriConverterInterface;
-use App\Entity\User;
+use App\Form\LoginFormType;
+use App\Form\RegistrationFormType;
+use App\Repository\UserRepository;
+use App\Security\EmailVerifier;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
-use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Mime\Address;
+use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
+use Symfony\Contracts\Translation\TranslatorInterface;
+use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
-/**
- *
- */
class SecurityController extends AbstractController
{
- #[Route(path: '/login', name: 'app_login')] // *** method post
- public function login(AuthenticationUtils $authenticationUtils, IriConverterInterface $iriConverter): Response
- {
- /** @var User $user */
- $user = $this->getUser() ?? null;
-
- return new Response(content: null, status: 204, headers: [
- 'Location' => $iriConverter->getIriFromItem(item: $user)
- ]);
-
+ public function __construct(private readonly EmailVerifier $emailVerifier)
+ {
+ // empty body
}
-
- /*
- return $this->render(view: 'security/login.html.twig', parameters: [
- 'error' => $authenticationUtils->getLastAuthenticationError(),
- 'last_username' => $authenticationUtils->getLastUsername(),
+
+ #[Route(path: '/login', name: 'app_login')]
+ public function index(AuthenticationUtils $authenticationUtils): Response
+ {
+ // get the login error if there is one
+ if ($error = $authenticationUtils->getLastAuthenticationError()) {
+ $this->addFlash(type: 'error', message: $error->getMessageKey());
+ }
+
+ // last username entered by the user
+ $lastUsername = $authenticationUtils->getLastUsername();
+
+ return $this->render(view: '@default/security/login.html.twig', parameters: [
+ 'last_username' => $lastUsername,
+ 'error' => '',
]);
- *
}
- /**
- * @return mixed
- */
- #[Route(path: '/logout', name: 'app_logout')]
- public function logout(): never
+
+ #[Route(path: '/register', name: 'app_register')]
+ public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
{
- throw new Exception(message: 'Logout should never be reached.');
+ $form = $this->createForm(type: RegistrationFormType::class);
+ $form->handleRequest(request: $request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $user = $form->getData();
+ // hash the plain password
+ $user->setPassword(
+ password: $userPasswordHasher->hashPassword(
+ user: $user,
+ plainPassword: $form->get(name: 'password')->getData()
+ )
+ );
+
+ if ($form->get(name: 'agreeTerms')->getData()) {
+ $user->agreeTerms();
+ } // no else, we already confirmed in the form itself
+ $entityManager->persist(entity: $user);
+ $entityManager->flush();
+
+ // generate a signed url and email it to the user
+ $this->emailVerifier->sendEmailConfirmation(verifyEmailRouteName: 'app_verify_email', user: $user,
+ email: (new TemplatedEmail())
+ ->from(new Address(address: 'info@24unix.net', name: '24unix.net'))
+ ->to($user->getEmail())
+ ->subject(subject: 'Please Confirm your Email')
+ ->htmlTemplate(template: '@default/security/mail/registration.html.twig')
+ ->context(context: [
+ 'username' => $user->getUsername()
+ ])
+ );
+
+ return $this->render(view: '@default/security/registration_finished.html.twig');
+ }
+
+ return $this->render(view: '@default/security/register.html.twig', parameters: [
+ 'registrationForm' => $form->createView(),
+ ]);
}
+
+ #[Route(path: '/verify/email', name: 'app_verify_email')]
+ public function verifyUserEmail(Request $request, TranslatorInterface $translator, UserRepository $userRepository): Response
+ {
+ $id = $request->get(key: 'id');
+
+ if ($id === null) {
+ return $this->redirectToRoute(route: 'app_register');
+ }
+
+ $user = $userRepository->find($id);
+
+ if ($user === null) {
+ return $this->redirectToRoute(route: 'app_register');
+ }
+
+ // validate email confirmation link, sets User::isVerified=true and persists
+ try {
+ $this->emailVerifier->handleEmailConfirmation(request: $request, user: $user);
+ } catch (VerifyEmailExceptionInterface $exception) {
+ $this->addFlash(type: 'verify_email_error', message: $translator->trans(id: $exception->getReason(), parameters: [], domain: 'VerifyEmailBundle'));
+
+ return $this->redirectToRoute(route: 'app_main');
+ }
+
+ $this->addFlash(type: 'success', message: 'Your email address has been verified.');
+
+ return $this->redirectToRoute(route: 'app_main');
+ }
+
}
diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php
index 41b5633..ed6ca09 100644
--- a/src/Controller/UserController.php
+++ b/src/Controller/UserController.php
@@ -3,9 +3,13 @@
namespace App\Controller;
use App\Entity\User;
+use App\Form\EditProfileFormType;
use App\Repository\UserRepository;
+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\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
@@ -13,31 +17,56 @@ use Symfony\Component\Security\Core\Exception\UserNotFoundException;
/**
* Class UserController.
*/
-class UserController extends AbstractController
+class UserController extends BaseController
{
#[Route(path: '/profile/edit/{username}', name: 'app_profile_edit')]
- public function editProfile(UserRepository $userRepository, string $username = ''): Response
+ public function editProfile(Request $request, UserRepository $userRepository, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, string $username = ''): Response
{
- /* var User $user */
- if ($username === '') {
- if ($this->isGranted(attribute: 'ROLE_USER')) {
- $user = $this->getUser();
- } else {
- throw new AccessDeniedException(message: 'You need to be logged in.');
- }
- } else {
+ if ($username !== '') {
if ($this->isGranted(attribute: 'ROLE_ADMIN')) {
$user = $userRepository->findOneBy([
'username' => $username,
]);
+ } else {
+ throw new AccessDeniedException(message: 'Only admins are allowed to edit Profiles.');
}
+ } else {
+ $user = $this->getUser();
}
+ $form = $this->createForm(type: EditProfileFormType::class, data: $user);
+ $form->handleRequest(request: $request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $user = $form->getData();
+ // if there's a new password, use it
+
+ if ($form->get(name: 'newPassword')->getData())
+ $user->setPassword(
+ password: $userPasswordHasher->hashPassword(
+ user: $user,
+ plainPassword: $form->get(name: 'newPassword')->getData()
+ )
+ );
+
+ $entityManager->persist(entity: $user);
+ $entityManager->flush();
+
+ return $this->redirectToRoute(route: 'app_main');
+ };
+
+ $user = $form->getData();
+ // hash the plain password
+
+
+ return $this->renderForm(view: '@default/user/edit_profile.html.twig', parameters: [
+ 'user' => $user,
+ 'userForm' => $form
+ ]);
+
+
if (isset($user)) {
- return $this->render(view: 'user/edit_profile.html.twig', parameters: [
- 'user' => $user,
- ]);
} else {
throw new UserNotFoundException();
}
diff --git a/src/Entity/ResetPasswordRequest.php b/src/Entity/ResetPasswordRequest.php
new file mode 100644
index 0000000..5f64973
--- /dev/null
+++ b/src/Entity/ResetPasswordRequest.php
@@ -0,0 +1,39 @@
+user = $user;
+ $this->initialize(expiresAt: $expiresAt, selector: $selector, hashedToken: $hashedToken);
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getUser(): object
+ {
+ return $this->user;
+ }
+}
diff --git a/src/Entity/User.php b/src/Entity/User.php
index 7b74d4e..e8b05fc 100644
--- a/src/Entity/User.php
+++ b/src/Entity/User.php
@@ -2,48 +2,40 @@
namespace App\Entity;
-use ApiPlatform\Core\Annotation\ApiFilter;
-use ApiPlatform\Core\Annotation\ApiResource;
-use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Repository\UserRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
+use Stringable;
+use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Validator\Constraints as Assert;
-/**
- * => ["security" => "is_granted('ROLE_ADMIN') or object.owner == user"]
-attributes : ['security' => 'is_granted("ROLE_USER")']
-
- */
#[ORM\Entity(repositoryClass: UserRepository::class), ORM\HasLifecycleCallbacks]
-#[ApiResource(
- collectionOperations: ['get', 'post'],
- itemOperations : ['get'],
-)]
-#[ApiFilter(filterClass: SearchFilter::class, properties: ['username' => 'exact'])]
+#[UniqueEntity(fields: ['username', 'email'], message: 'There is already an account with this username or email.')]
-class User implements UserInterface, PasswordAuthenticatedUserInterface, \Stringable
+class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
- #[ORM\Column(type: 'string', length: 180, unique: true)]
+ #[ORM\Column(type: 'string', length: 180, unique: true, nullable: false)]
private string $username;
#[ORM\Column(type: 'json')]
private array $roles = [];
- #[ORM\Column(type: 'string')]
+ #[ORM\Column(type: 'string', nullable: false)]
private string $password;
- private string $plainPassword;
-
- #[ORM\Column(type: 'string', length: 255)]
+ #[ORM\Column(type: 'string', length: 255, nullable: false)]
+ #[Assert\Email(
+ message: 'The eMail {{ value }} is not a valid eMail.'
+ )]
private string $email;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
@@ -67,15 +59,18 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, \String
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
private $modifiedAt;
+ #[ORM\Column(type: 'boolean')]
+ private $isVerified = false;
+
+ #[ORM\Column]
+ private ?DateTimeImmutable $agreedTermsAt = null;
+
public function __construct()
{
$this->projects = new ArrayCollection();
$this->pages = new ArrayCollection();
}
- /**
- * @return string|null
- */
public function __toString(): string
{
return $this->username;
@@ -86,11 +81,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, \String
return $this->id;
}
- public function getPlainPassword(): string
- {
- return $this->plainPassword;
- }
-
public function getUsername(): ?string
{
return $this->username;
@@ -293,9 +283,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, \String
* @return string
*/
public function getAvatarUri()
- {
- return 'avatar';
- }
+ {
+ return 'avatar';
+ }
#[ORM\PrePersist]
public function onPrePersist(): void
@@ -308,4 +298,28 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface, \String
{
$this->modifiedAt = new DateTimeImmutable(datetime: 'now');
}
+
+ public function isVerified(): bool
+ {
+ return $this->isVerified;
+ }
+
+ public function setIsVerified(bool $isVerified): self
+ {
+ $this->isVerified = $isVerified;
+
+ return $this;
+ }
+
+ public function getAgreedTermsAt(): ?DateTimeImmutable
+ {
+ return $this->agreedTermsAt;
+ }
+
+ public function agreeTerms(): self
+ {
+ $this->agreedTermsAt = new DateTimeImmutable();
+
+ return $this;
+ }
}
diff --git a/src/Form/ChangePasswordFormType.php b/src/Form/ChangePasswordFormType.php
new file mode 100644
index 0000000..514289d
--- /dev/null
+++ b/src/Form/ChangePasswordFormType.php
@@ -0,0 +1,54 @@
+add(child: 'plainPassword', type: RepeatedType::class, options: [
+ 'type' => PasswordType::class,
+ 'options' => [
+ 'attr' => [
+ 'autocomplete' => 'new-password',
+ ],
+ ],
+ 'first_options' => [
+ 'constraints' => [
+ new NotBlank(options: [
+ 'message' => 'Please enter a password',
+ ]),
+ new Length(exactly: [
+ 'min' => 6,
+ 'minMessage' => 'Your password should be at least {{ limit }} characters',
+ // max length allowed by Symfony for security reasons
+ 'max' => 4096,
+ ]),
+ ],
+ 'label' => 'New password',
+ ],
+ 'second_options' => [
+ 'label' => 'Repeat Password',
+ ],
+ 'invalid_message' => 'The password fields must match.',
+ // Instead of being set onto the object directly,
+ // this is read and encoded in the controller
+ 'mapped' => false,
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults(defaults: []);
+ }
+}
diff --git a/src/Form/EditProfileFormType.php b/src/Form/EditProfileFormType.php
new file mode 100644
index 0000000..65d98c4
--- /dev/null
+++ b/src/Form/EditProfileFormType.php
@@ -0,0 +1,45 @@
+add(child: 'username')
+ ->add(child: 'firstName')
+ ->add(child: 'lastName')
+ ->add(child: 'email', type: EmailType::class)
+ ->add(child: 'newPassword', type: RepeatedType::class, options: [
+ 'type' => PasswordType::class,
+ 'mapped' => false,
+ 'invalid_message' => 'The password fields must match.',
+ 'options' => ['attr' => ['class' => 'password-field', 'autocomplete' => 'off']],
+ 'required' => false,
+ 'first_options' => ['label' => 'Password'],
+ 'second_options' => ['label' => 'Repeat Password (only needed if you want to update the password'],
+ 'constraints' => [new Length(exactly: ['min' => 6])]
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults(defaults: [
+ 'data_class' => User::class,
+ 'csrf_protection' => true,
+ 'csrf_field_name' => '_csrf_token',
+ 'csrf_token_id' => 'authenticate'
+ ]);
+ }
+}
diff --git a/src/Form/RegistrationFormType.php b/src/Form/RegistrationFormType.php
new file mode 100644
index 0000000..90a2bb1
--- /dev/null
+++ b/src/Form/RegistrationFormType.php
@@ -0,0 +1,49 @@
+add(child: 'username')
+ ->add(child: 'email', type: EmailType::class)
+ ->add(child: 'password', type: RepeatedType::class, options: [
+ 'type' => PasswordType::class,
+ 'invalid_message' => 'The password fields must match.',
+ 'options' => ['attr' => ['class' => 'password-field']],
+ 'required' => true,
+ 'first_options' => ['label' => 'Password'],
+ 'second_options' => ['label' => 'Repeat Password'],
+ 'constraints' => [new Length(exactly: ['min' => 6])]
+ ])
+ ->add(child: 'agreeTerms', type: CheckboxType::class, options: [
+ 'mapped' => false,
+ 'constraints' => [
+ new IsTrue(options: [
+ 'message' => 'You should agree to our terms.',
+ ]),
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults(defaults: [
+ 'data_class' => User::class,
+ ]);
+ }
+}
diff --git a/src/Form/ResetPasswordRequestFormType.php b/src/Form/ResetPasswordRequestFormType.php
new file mode 100644
index 0000000..46bfccb
--- /dev/null
+++ b/src/Form/ResetPasswordRequestFormType.php
@@ -0,0 +1,31 @@
+add(child: 'account', type: null, options: [
+ 'mapped' => false,
+ 'constraints' => [
+ new NotBlank(options: [
+ 'message' => 'Please enter your email or username',
+ ]),
+ ],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver): void
+ {
+ $resolver->setDefaults(defaults: []);
+ }
+}
diff --git a/src/Repository/ResetPasswordRequestRepository.php b/src/Repository/ResetPasswordRequestRepository.php
new file mode 100644
index 0000000..658c4a6
--- /dev/null
+++ b/src/Repository/ResetPasswordRequestRepository.php
@@ -0,0 +1,51 @@
+
+ *
+ * @method ResetPasswordRequest|null find($id, $lockMode = null, $lockVersion = null)
+ * @method ResetPasswordRequest|null findOneBy(array $criteria, array $orderBy = null)
+ * @method ResetPasswordRequest[] findAll()
+ * @method ResetPasswordRequest[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class ResetPasswordRequestRepository extends ServiceEntityRepository implements ResetPasswordRequestRepositoryInterface
+{
+ use ResetPasswordRequestRepositoryTrait;
+
+ public function __construct(ManagerRegistry $registry)
+ {
+ parent::__construct($registry, ResetPasswordRequest::class);
+ }
+
+ public function save(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);
+ }
+}
diff --git a/src/Security/EmailVerifier.php b/src/Security/EmailVerifier.php
new file mode 100644
index 0000000..1d45afc
--- /dev/null
+++ b/src/Security/EmailVerifier.php
@@ -0,0 +1,54 @@
+verifyEmailHelper->generateSignature(
+ routeName: $verifyEmailRouteName,
+ userId: $user->getId(),
+ userEmail: $user->getEmail(),
+ extraParams: ['id' => $user->getId()]
+ );
+
+ $context = $email->getContext();
+ $context['signedUrl'] = $signatureComponents->getSignedUrl();
+ $context['expiresAtMessageKey'] = $signatureComponents->getExpirationMessageKey();
+ $context['expiresAtMessageData'] = $signatureComponents->getExpirationMessageData();
+
+ $email->context(context: $context);
+
+ $this->mailer->send(message: $email);
+ }
+
+ /**
+ * @throws VerifyEmailExceptionInterface
+ */
+ public function handleEmailConfirmation(Request $request, User /*UserInterface*/ $user): void
+ {
+ $this->verifyEmailHelper->validateEmailConfirmation(signedUrl: $request->getUri(), userId: $user->getId(), userEmail: $user->getEmail());
+
+ $user->setIsVerified(isVerified: true);
+
+ $this->entityManager->persist(entity: $user);
+ $this->entityManager->flush();
+ }
+}
diff --git a/src/Security/LoginFormAuthenticator.php b/src/Security/LoginFormAuthenticator.php
index 682f3e9..1f99595 100644
--- a/src/Security/LoginFormAuthenticator.php
+++ b/src/Security/LoginFormAuthenticator.php
@@ -3,12 +3,17 @@
namespace App\Security;
use App\Entity\User;
+use App\Form\LoginFormType;
use App\Repository\UserRepository;
+use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
@@ -16,7 +21,9 @@ use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials;
+use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
+use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
/**
@@ -38,15 +45,13 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
$csrfToken = $request->request->get(key: '_csrf_token');
$request->getSession()->set(name: Security::LAST_USERNAME, value: $username);
-
- dd("here");
return new Passport(
- userBadge: new UserBadge(userIdentifier: $username, userLoader: function ($userIdentifier) {
- $user = $this->userRepository->findOneBy(['username' => $userIdentifier]);
+ userBadge: new UserBadge(userIdentifier: $username, userLoader: function ($username) {
+ $user = $this->userRepository->findOneBy(['username' => $username]);
if (!$user) {
- $user = $this->userRepository->findOneBy(['email' => $userIdentifier]);
+ $user = $this->userRepository->findOneBy(['email' => $username]);
}
if (!$user) {
@@ -56,10 +61,7 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
return $user;
}),
- // remove me later for PasswordCredentials()
- credentials: new CustomCredentials(customCredentialsChecker: fn($credentials, User $user) => $credentials === 'test', credentials : $password),
-
- // new PasswordCredentials($password),
+ credentials: new PasswordCredentials(password: $password),
badges: [
new CsrfTokenBadge(csrfTokenId: 'authenticate', csrfToken: $csrfToken),
new RememberMeBadge(),
@@ -82,4 +84,5 @@ class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
return $this->router->generate(name: 'app_login');
}
+
}
diff --git a/symfony.lock b/symfony.lock
index 71cfc9a..6b8f720 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -1,18 +1,4 @@
{
- "api-platform/core": {
- "version": "2.7",
- "recipe": {
- "repo": "github.com/symfony/recipes",
- "branch": "main",
- "version": "2.5",
- "ref": "05b57782a78c21a664a42055dc11cf1954ca36bb"
- },
- "files": [
- "config/packages/api_platform.yaml",
- "config/routes/api_platform.yaml",
- "src/Entity/.gitignore"
- ]
- },
"doctrine/annotations": {
"version": "1.13",
"recipe": {
@@ -303,5 +289,23 @@
"package.json",
"webpack.config.js"
]
+ },
+ "symfonycasts/reset-password-bundle": {
+ "version": "1.16",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "1.0",
+ "ref": "97c1627c0384534997ae1047b93be517ca16de43"
+ },
+ "files": [
+ "config/packages/reset_password.yaml"
+ ]
+ },
+ "symfonycasts/verify-email-bundle": {
+ "version": "v1.12.0"
+ },
+ "twig/extra-bundle": {
+ "version": "v3.4.0"
}
}
diff --git a/templates/base.html.twig b/templates/base.html.twig
deleted file mode 100644
index d4f83f7..0000000
--- a/templates/base.html.twig
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- {% block title %}Welcome!{% endblock %}
-
- {# Run `composer require symfony/webpack-encore-bundle` to start using Symfony UX #}
- {% block stylesheets %}
- {{ encore_entry_link_tags('app') }}
- {% endblock %}
-
- {% block javascripts %}
- {{ encore_entry_script_tags('app') }}
- {% endblock %}
-
-
- {% block body %}{% endblock %}
-
-
diff --git a/templates/themes/default/_header.html.twig b/templates/themes/default/_header.html.twig
index 08f267b..523479c 100644
--- a/templates/themes/default/_header.html.twig
+++ b/templates/themes/default/_header.html.twig
@@ -21,7 +21,7 @@
{% if is_granted('ROLE_USER') %}
+ class="btn btn-primary dropdown-toggle button-login">
{{ app.user.username }}
diff --git a/templates/themes/default/base.html.twig b/templates/themes/default/base.html.twig
index 5125835..3d6e4c6 100644
--- a/templates/themes/default/base.html.twig
+++ b/templates/themes/default/base.html.twig
@@ -38,36 +38,36 @@
{% include '@default/_header.html.twig' %}
-
+
{% for message in app.flashes('success') %}
@@ -82,7 +82,7 @@
{% endfor %}
-
+
{% block body %}
Quote of the Moment
diff --git a/templates/themes/default/pages/imprint.html.twig b/templates/themes/default/pages/imprint.html.twig
index 027999e..a957045 100644
--- a/templates/themes/default/pages/imprint.html.twig
+++ b/templates/themes/default/pages/imprint.html.twig
@@ -1,13 +1,16 @@
-{% extends template_dir ~ 'base.html.twig' %}
+{% extends '@default/base.html.twig' %}
{% block title %}Imprint{% endblock %}
{% block body %}
-
This page is only available in German, as the server is located in Germany.
+
This page is only available in German, as the server is located in Germany.
-
Inhaltlich Verantwortlicher gemäß § 55 Abs. 2RStV: Michael Espey, Große Kirchreihe 27, 25377 Kollmar
+
Inhaltlich Verantwortlicher gemäß § 55 Abs. 2RStV:
+ Michael Espey
+ Große Kirchreihe 27
+ 25377 Kollmar
eMail: webmaster (AT) 24unix.net
diff --git a/templates/themes/default/pages/privacy.html.twig b/templates/themes/default/pages/privacy.html.twig
index 681bd24..a485919 100644
--- a/templates/themes/default/pages/privacy.html.twig
+++ b/templates/themes/default/pages/privacy.html.twig
@@ -1,4 +1,4 @@
-{% extends template_dir ~'base.html.twig' %}
+{% extends '@default/base.html.twig' %}
{% block title %}Privacy{% endblock %}
diff --git a/templates/themes/default/projects/index.html.twig b/templates/themes/default/projects/index.html.twig
new file mode 100644
index 0000000..bf72b99
--- /dev/null
+++ b/templates/themes/default/projects/index.html.twig
@@ -0,0 +1,70 @@
+{# templates/projects/index.html.twig #}
+{% extends '@default/base.html.twig' %}
+
+{% block title %} Projects {% endblock %}
+
+{% block body %}
+
+
+
This is an overview of my current public (and open source) projects.
+
+
+
+ {% for project in projects %}
+
+ {% endfor %}
+
+
+ {% if is_granted('ROLE_ADMIN') %}
+
+ {% endif %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/templates/themes/default/projects/show.html.twig b/templates/themes/default/projects/show.html.twig
new file mode 100644
index 0000000..c6d0dec
--- /dev/null
+++ b/templates/themes/default/projects/show.html.twig
@@ -0,0 +1,35 @@
+{# templates/blog/blog_show.html.twig #}
+{% extends '@default/base.html.twig' %}
+
+{% block title %}Projects{% endblock %}
+
+{% block body %}
+
+
+
+ {% if is_granted('ROLE_ADMIN') %}
+
+ {% endif %}
+
+
+
+
{{ project.name }}
+
+
+
+
+
+ {{ readme | markdown_to_html }}
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/templates/themes/default/security/forgot_password.html.twig b/templates/themes/default/security/forgot_password.html.twig
new file mode 100644
index 0000000..c397c08
--- /dev/null
+++ b/templates/themes/default/security/forgot_password.html.twig
@@ -0,0 +1,22 @@
+{% extends '@default/base.html.twig' %}
+
+{% block title %}Reset your password{% endblock %}
+
+{% block body %}
+ {% for flash_error in app.flashes('reset_password_error') %}
+
{{ flash_error }}
+ {% endfor %}
+
Reset your password
+
+ {{ form_start(requestForm) }}
+ {{ form_row(requestForm.account) }}
+
+
+ Enter your email address or your username and we will send you a
+ link to reset your password.
+
+
+
+
Send password reset email
+ {{ form_end(requestForm) }}
+{% endblock %}
diff --git a/templates/security/login.html.twig b/templates/themes/default/security/login.html.twig
similarity index 72%
rename from templates/security/login.html.twig
rename to templates/themes/default/security/login.html.twig
index a2bd63c..f081693 100644
--- a/templates/security/login.html.twig
+++ b/templates/themes/default/security/login.html.twig
@@ -1,23 +1,27 @@
-{% extends '../themes/default/base.html.twig' %}
+{% extends '@default/base.html.twig' %}
{% block title %}Log In!{% endblock %}
{% block body %}
-
+
diff --git a/templates/themes/default/security/mail/recovery.html.twig b/templates/themes/default/security/mail/recovery.html.twig
new file mode 100644
index 0000000..a651258
--- /dev/null
+++ b/templates/themes/default/security/mail/recovery.html.twig
@@ -0,0 +1,9 @@
+
Hi!
+
+
To reset your password, please visit the following link
+
+
Reset password
+
+
This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.
+
+
Cheers!
diff --git a/templates/themes/default/security/mail/registration.html.twig b/templates/themes/default/security/mail/registration.html.twig
new file mode 100644
index 0000000..665506f
--- /dev/null
+++ b/templates/themes/default/security/mail/registration.html.twig
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Hi {{ username }}, please confirm your email!
+
+
+ Please confirm your email address by clicking the following link:
+ Confirm my Email .
+
+ This link will expire in {{ expiresAtMessageKey|trans(expiresAtMessageData, 'VerifyEmailBundle') }}.
+
+
+
+ Kind regards,
+ 24unix.net
+
+
+
+
diff --git a/templates/themes/default/security/recovery_mail_sent.html.twig b/templates/themes/default/security/recovery_mail_sent.html.twig
new file mode 100644
index 0000000..8786623
--- /dev/null
+++ b/templates/themes/default/security/recovery_mail_sent.html.twig
@@ -0,0 +1,11 @@
+{% extends '@default/base.html.twig' %}
+
+{% block title %}Password Reset Email Sent{% endblock %}
+
+{% block body %}
+
+ If an account matching your email exists, then an email was just sent that contains a link that you can use to reset your password.
+ This link will expire in {{ resetToken.expirationMessageKey|trans(resetToken.expirationMessageData, 'ResetPasswordBundle') }}.
+
+
If you don't receive an email please check your spam folder or try again .
+{% endblock %}
diff --git a/templates/themes/default/security/register.html.twig b/templates/themes/default/security/register.html.twig
new file mode 100644
index 0000000..6b3a3bc
--- /dev/null
+++ b/templates/themes/default/security/register.html.twig
@@ -0,0 +1,60 @@
+{% extends '@default/base.html.twig' %}
+{% form_theme registrationForm _self %}
+
+{% block title %}Register{% endblock %}
+
+
+{% block form_row %}
+ {%- set widget_attr = {} -%}
+ {%- if help is not empty -%}
+ {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
+ {%- endif -%}
+
+ {{- form_label(form, null, {
+ label_attr: { class: 'sr-only' }
+ }) -}}
+ {{- form_errors(form) -}}
+ {{- form_widget(form, widget_attr) -}}
+ {{- form_help(form) -}}
+{% endblock %}
+
+
+{% block body %}
+ {% for flash_error in app.flashes('verify_email_error') %}
+
{{ flash_error }}
+ {% endfor %}
+
+
+
+
+
Register
+
+ {{ form_start(registrationForm, {
+ attr: { class: 'form-signin' }
+ }) }}
+
+ {{ form_row(registrationForm.username, {
+ attr: { placeholder: 'User name' }
+ }) }}
+ {{ form_row(registrationForm.email, {
+ attr: { placeholder: 'eMail' }
+ }) }}
+ {{ form_row(registrationForm.password.first, {
+ attr: { placeholder: 'Password'}
+ }) }}
+ {{ form_row(registrationForm.password.second, {
+ attr: { placeholder: 'Confirm password'}
+ }) }}
+
+ {{ form_row(registrationForm.agreeTerms) }}
+
+ Register
+ {{ form_end(registrationForm) }}
+
+
+
+
+
+{% endblock %}
+
+
diff --git a/templates/themes/default/security/registration_finished.html.twig b/templates/themes/default/security/registration_finished.html.twig
new file mode 100644
index 0000000..5f12a74
--- /dev/null
+++ b/templates/themes/default/security/registration_finished.html.twig
@@ -0,0 +1,19 @@
+{% extends '@default/base.html.twig' %}
+
+{% block title %}Registration finished{% endblock %}
+
+{% block body %}
+
+
+
+{% endblock %}
+
+
diff --git a/templates/themes/default/security/reset_password.html.twig b/templates/themes/default/security/reset_password.html.twig
new file mode 100644
index 0000000..c69b259
--- /dev/null
+++ b/templates/themes/default/security/reset_password.html.twig
@@ -0,0 +1,12 @@
+{% extends '@default/base.html.twig' %}
+
+{% block title %}Reset your password{% endblock %}
+
+{% block body %}
+
Reset your password
+
+ {{ form_start(resetForm) }}
+ {{ form_row(resetForm.plainPassword) }}
+
Reset password
+ {{ form_end(resetForm) }}
+{% endblock %}
diff --git a/templates/user/edit_profile.html.twig b/templates/themes/default/user/edit_profile.html.twig
similarity index 53%
rename from templates/user/edit_profile.html.twig
rename to templates/themes/default/user/edit_profile.html.twig
index 92fe40a..dfa8307 100644
--- a/templates/user/edit_profile.html.twig
+++ b/templates/themes/default/user/edit_profile.html.twig
@@ -1,4 +1,4 @@
-{% extends '../themes/default/base.html.twig' %}
+{% extends '@default/base.html.twig' %}
{% block title %}
Profile of {{ user.username }}
@@ -13,37 +13,29 @@
+
{{ user.username }}
{{ user.email }}
+ {{ form_start(userForm) }}
User Profile
-
-
-
Username
-
+
+ Save Profile
-
-
diff --git a/templates/user/list_users.html.twig b/templates/themes/default/user/list_users.html.twig
similarity index 100%
rename from templates/user/list_users.html.twig
rename to templates/themes/default/user/list_users.html.twig
diff --git a/templates/user/show_profile.html.twig b/templates/themes/default/user/show_profile.html.twig
similarity index 98%
rename from templates/user/show_profile.html.twig
rename to templates/themes/default/user/show_profile.html.twig
index aa6a11f..3232d8c 100644
--- a/templates/user/show_profile.html.twig
+++ b/templates/themes/default/user/show_profile.html.twig
@@ -1,4 +1,4 @@
-{% extends '../themes/default/base.html.twig' %}
+{% extends '@default/base.html.twig' %}
{% block title %}
Profile of {{ user.username }}