Initial commit
This commit is contained in:
parent
0cce30679a
commit
e8df5bf019
10
.env
10
.env
@ -25,8 +25,8 @@ APP_SECRET=0ac2ef94aa7fbf17c0fa7caca5d59ba8
|
|||||||
#
|
#
|
||||||
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
|
||||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
|
# DATABASE_URL="mysql://MyComments:Plentiful-Easiness-Gracious6-Boggle@127.0.0.1:3306/MyComments?serverVersion=11.1.2-MariaDB&charset=utf8mb4"
|
||||||
DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=15&charset=utf8"
|
DATABASE_URL="postgresql://app:Liqueur-Battalion7-Woof-Spokesman@127.0.0.1:5432/app?serverVersion=15&charset=utf8"
|
||||||
###< doctrine/doctrine-bundle ###
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
###> symfony/messenger ###
|
###> symfony/messenger ###
|
||||||
@ -39,3 +39,9 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
|
|||||||
###> symfony/mailer ###
|
###> symfony/mailer ###
|
||||||
# MAILER_DSN=null://null
|
# MAILER_DSN=null://null
|
||||||
###< symfony/mailer ###
|
###< symfony/mailer ###
|
||||||
|
|
||||||
|
###> symfony/lock ###
|
||||||
|
# Choose one of the stores below
|
||||||
|
# postgresql+advisory://db_user:db_password@localhost/db_name
|
||||||
|
LOCK_DSN=flock
|
||||||
|
###< symfony/lock ###
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,3 +18,6 @@
|
|||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
/phpunit.xml
|
/phpunit.xml
|
||||||
###< symfony/phpunit-bridge ###
|
###< symfony/phpunit-bridge ###
|
||||||
|
|
||||||
|
# IDE folders
|
||||||
|
.idea
|
20
LICENSE
20
LICENSE
@ -1,9 +1,21 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 skylord123
|
Copyright (c) 2023 MyComments
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -10,6 +10,7 @@
|
|||||||
"doctrine/doctrine-bundle": "^2.10",
|
"doctrine/doctrine-bundle": "^2.10",
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.2",
|
"doctrine/doctrine-migrations-bundle": "^3.2",
|
||||||
"doctrine/orm": "^2.16",
|
"doctrine/orm": "^2.16",
|
||||||
|
"gedmo/doctrine-extensions": "^3.13",
|
||||||
"phpdocumentor/reflection-docblock": "^5.3",
|
"phpdocumentor/reflection-docblock": "^5.3",
|
||||||
"phpstan/phpdoc-parser": "^1.24",
|
"phpstan/phpdoc-parser": "^1.24",
|
||||||
"symfony/asset": "6.3.*",
|
"symfony/asset": "6.3.*",
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"symfony/framework-bundle": "6.3.*",
|
"symfony/framework-bundle": "6.3.*",
|
||||||
"symfony/http-client": "6.3.*",
|
"symfony/http-client": "6.3.*",
|
||||||
"symfony/intl": "6.3.*",
|
"symfony/intl": "6.3.*",
|
||||||
|
"symfony/lock": "6.3.*",
|
||||||
"symfony/mailer": "6.3.*",
|
"symfony/mailer": "6.3.*",
|
||||||
"symfony/mime": "6.3.*",
|
"symfony/mime": "6.3.*",
|
||||||
"symfony/monolog-bundle": "^3.0",
|
"symfony/monolog-bundle": "^3.0",
|
||||||
@ -29,6 +31,7 @@
|
|||||||
"symfony/process": "6.3.*",
|
"symfony/process": "6.3.*",
|
||||||
"symfony/property-access": "6.3.*",
|
"symfony/property-access": "6.3.*",
|
||||||
"symfony/property-info": "6.3.*",
|
"symfony/property-info": "6.3.*",
|
||||||
|
"symfony/rate-limiter": "6.3.*",
|
||||||
"symfony/runtime": "6.3.*",
|
"symfony/runtime": "6.3.*",
|
||||||
"symfony/security-bundle": "6.3.*",
|
"symfony/security-bundle": "6.3.*",
|
||||||
"symfony/serializer": "6.3.*",
|
"symfony/serializer": "6.3.*",
|
||||||
|
403
composer.lock
generated
403
composer.lock
generated
@ -4,8 +4,133 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e077926b0d83c217ece524f4a3d61fa8",
|
"content-hash": "0e74667a94096c60a3ca270a79c1331d",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "behat/transliterator",
|
||||||
|
"version": "v1.5.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Behat/Transliterator.git",
|
||||||
|
"reference": "baac5873bac3749887d28ab68e2f74db3a4408af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Behat/Transliterator/zipball/baac5873bac3749887d28ab68e2f74db3a4408af",
|
||||||
|
"reference": "baac5873bac3749887d28ab68e2f74db3a4408af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"chuyskywalker/rolling-curl": "^3.1",
|
||||||
|
"php-yaoi/php-yaoi": "^1.0",
|
||||||
|
"phpunit/phpunit": "^8.5.25 || ^9.5.19"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Behat\\Transliterator\\": "src/Behat/Transliterator"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Artistic-1.0"
|
||||||
|
],
|
||||||
|
"description": "String transliterator",
|
||||||
|
"keywords": [
|
||||||
|
"i18n",
|
||||||
|
"slug",
|
||||||
|
"transliterator"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Behat/Transliterator/issues",
|
||||||
|
"source": "https://github.com/Behat/Transliterator/tree/v1.5.0"
|
||||||
|
},
|
||||||
|
"time": "2022-03-30T09:27:43+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/annotations",
|
||||||
|
"version": "2.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/annotations.git",
|
||||||
|
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||||
|
"reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/lexer": "^2 || ^3",
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"php": "^7.2 || ^8.0",
|
||||||
|
"psr/cache": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/cache": "^2.0",
|
||||||
|
"doctrine/coding-standard": "^10",
|
||||||
|
"phpstan/phpstan": "^1.8.0",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||||
|
"symfony/cache": "^5.4 || ^6",
|
||||||
|
"vimeo/psalm": "^4.10"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Docblock Annotations Parser",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
||||||
|
"keywords": [
|
||||||
|
"annotations",
|
||||||
|
"docblock",
|
||||||
|
"parser"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/annotations/issues",
|
||||||
|
"source": "https://github.com/doctrine/annotations/tree/2.0.1"
|
||||||
|
},
|
||||||
|
"time": "2023-02-02T22:02:53+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/cache",
|
"name": "doctrine/cache",
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
@ -1387,6 +1512,133 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-01-14T14:17:03+00:00"
|
"time": "2023-01-14T14:17:03+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "gedmo/doctrine-extensions",
|
||||||
|
"version": "v3.13.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine-extensions/DoctrineExtensions.git",
|
||||||
|
"reference": "291d0c527d2dc9ee07b888c9a4e2a179893f08ab"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine-extensions/DoctrineExtensions/zipball/291d0c527d2dc9ee07b888c9a4e2a179893f08ab",
|
||||||
|
"reference": "291d0c527d2dc9ee07b888c9a4e2a179893f08ab",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"behat/transliterator": "^1.2",
|
||||||
|
"doctrine/annotations": "^1.13 || ^2.0",
|
||||||
|
"doctrine/collections": "^1.2 || ^2.0",
|
||||||
|
"doctrine/common": "^2.13 || ^3.0",
|
||||||
|
"doctrine/event-manager": "^1.2 || ^2.0",
|
||||||
|
"doctrine/persistence": "^2.2 || ^3.0",
|
||||||
|
"php": "^7.2 || ^8.0",
|
||||||
|
"psr/cache": "^1 || ^2 || ^3",
|
||||||
|
"symfony/cache": "^4.4 || ^5.3 || ^6.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.1 || ^3.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<2.13.1 || ^3.0 <3.2",
|
||||||
|
"doctrine/mongodb-odm": "<2.3",
|
||||||
|
"doctrine/orm": "<2.10.2 || 2.16.0 || 2.16.1",
|
||||||
|
"sebastian/comparator": "<2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/cache": "^1.11 || ^2.0",
|
||||||
|
"doctrine/dbal": "^2.13.1 || ^3.2",
|
||||||
|
"doctrine/doctrine-bundle": "^2.3",
|
||||||
|
"doctrine/mongodb-odm": "^2.3",
|
||||||
|
"doctrine/orm": "^2.10.2",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.4.0 <3.10",
|
||||||
|
"nesbot/carbon": "^2.55",
|
||||||
|
"phpstan/phpstan": "^1.10.2",
|
||||||
|
"phpstan/phpstan-doctrine": "^1.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0",
|
||||||
|
"phpunit/phpunit": "^8.5 || ^9.5",
|
||||||
|
"rector/rector": "^0.15.20",
|
||||||
|
"symfony/console": "^4.4 || ^5.3 || ^6.0",
|
||||||
|
"symfony/phpunit-bridge": "^6.0",
|
||||||
|
"symfony/yaml": "^4.4 || ^5.3 || ^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"doctrine/mongodb-odm": "to use the extensions with the MongoDB ODM",
|
||||||
|
"doctrine/orm": "to use the extensions with the ORM"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.13-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Gedmo\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Gediminas Morkevicius",
|
||||||
|
"email": "gediminas.morkevicius@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gustavo Falco",
|
||||||
|
"email": "comfortablynumb84@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "David Buchmann",
|
||||||
|
"email": "david@liip.ch"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Doctrine behavioral extensions",
|
||||||
|
"homepage": "http://gediminasm.org/",
|
||||||
|
"keywords": [
|
||||||
|
"Blameable",
|
||||||
|
"behaviors",
|
||||||
|
"doctrine",
|
||||||
|
"extensions",
|
||||||
|
"gedmo",
|
||||||
|
"loggable",
|
||||||
|
"nestedset",
|
||||||
|
"odm",
|
||||||
|
"orm",
|
||||||
|
"sluggable",
|
||||||
|
"sortable",
|
||||||
|
"timestampable",
|
||||||
|
"translatable",
|
||||||
|
"tree",
|
||||||
|
"uploadable"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"email": "gediminas.morkevicius@gmail.com",
|
||||||
|
"issues": "https://github.com/doctrine-extensions/DoctrineExtensions/issues",
|
||||||
|
"source": "https://github.com/doctrine-extensions/DoctrineExtensions/tree/v3.13.0",
|
||||||
|
"wiki": "https://github.com/Atlantic18/DoctrineExtensions/tree/main/doc"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/l3pp4rd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/mbabker",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/phansys",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/stof",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-09-06T13:16:12+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "monolog/monolog",
|
"name": "monolog/monolog",
|
||||||
"version": "3.4.0",
|
"version": "3.4.0",
|
||||||
@ -4061,6 +4313,85 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-07-20T07:43:09+00:00"
|
"time": "2023-07-20T07:43:09+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/lock",
|
||||||
|
"version": "v6.3.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/lock.git",
|
||||||
|
"reference": "cde6dbd72d217024b1049d42a4519e713e2f18af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/lock/zipball/cde6dbd72d217024b1049d42a4519e713e2f18af",
|
||||||
|
"reference": "cde6dbd72d217024b1049d42a4519e713e2f18af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"psr/log": "^1|^2|^3",
|
||||||
|
"symfony/deprecation-contracts": "^2.5|^3"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<2.13",
|
||||||
|
"symfony/cache": "<6.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^2.13|^3.0",
|
||||||
|
"predis/predis": "^1.1|^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Lock\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jérémy Derussé",
|
||||||
|
"email": "jeremy@derusse.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Creates and manages locks, a mechanism to provide exclusive access to a shared resource",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"cas",
|
||||||
|
"flock",
|
||||||
|
"locking",
|
||||||
|
"mutex",
|
||||||
|
"redlock",
|
||||||
|
"semaphore"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/lock/tree/v6.3.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-06-28T15:25:15+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mailer",
|
"name": "symfony/mailer",
|
||||||
"version": "v6.3.0",
|
"version": "v6.3.0",
|
||||||
@ -5410,6 +5741,76 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-05-19T08:06:44+00:00"
|
"time": "2023-05-19T08:06:44+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/rate-limiter",
|
||||||
|
"version": "v6.3.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/rate-limiter.git",
|
||||||
|
"reference": "5223387e4017f26c8c61c46d8e39c11fe4d504b7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/rate-limiter/zipball/5223387e4017f26c8c61c46d8e39c11fe4d504b7",
|
||||||
|
"reference": "5223387e4017f26c8c61c46d8e39c11fe4d504b7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"symfony/options-resolver": "^5.4|^6.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"psr/cache": "^1.0|^2.0|^3.0",
|
||||||
|
"symfony/lock": "^5.4|^6.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\RateLimiter\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Wouter de Jong",
|
||||||
|
"email": "wouter@wouterj.nl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides a Token Bucket implementation to rate limit input and output in your application",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"limiter",
|
||||||
|
"rate-limiter"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/rate-limiter/tree/v6.3.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-07-13T14:29:38+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/routing",
|
"name": "symfony/routing",
|
||||||
"version": "v6.3.3",
|
"version": "v6.3.3",
|
||||||
|
2
config/packages/lock.yaml
Normal file
2
config/packages/lock.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
framework:
|
||||||
|
lock: '%env(LOCK_DSN)%'
|
@ -1,17 +1,57 @@
|
|||||||
|
framework:
|
||||||
|
rate_limiter:
|
||||||
|
# define 2 rate limiters (one for username+IP, the other for IP)
|
||||||
|
username_ip_login:
|
||||||
|
policy: token_bucket
|
||||||
|
limit: 5
|
||||||
|
rate: { interval: '5 minutes' }
|
||||||
|
|
||||||
|
ip_login:
|
||||||
|
policy: sliding_window
|
||||||
|
limit: 40
|
||||||
|
interval: '30 minutes'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# our custom login rate limiter
|
||||||
|
app.login_rate_limiter:
|
||||||
|
class: Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter
|
||||||
|
arguments:
|
||||||
|
# globalFactory is the limiter for IP
|
||||||
|
$globalFactory: '@limiter.ip_login'
|
||||||
|
# localFactory is the limiter for username+IP
|
||||||
|
$localFactory: '@limiter.username_ip_login'
|
||||||
|
|
||||||
security:
|
security:
|
||||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||||
password_hashers:
|
password_hashers:
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||||
providers:
|
providers:
|
||||||
users_in_memory: { memory: null }
|
# used to reload user from session & other features (e.g. switch_user)
|
||||||
|
app_user_provider:
|
||||||
|
entity:
|
||||||
|
class: App\Entity\User
|
||||||
|
property: email
|
||||||
firewalls:
|
firewalls:
|
||||||
dev:
|
dev:
|
||||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||||
security: false
|
security: false
|
||||||
main:
|
main:
|
||||||
lazy: true
|
lazy: true
|
||||||
provider: users_in_memory
|
provider: app_user_provider
|
||||||
|
|
||||||
|
form_login:
|
||||||
|
login_path: app_login
|
||||||
|
check_path: app_login
|
||||||
|
|
||||||
|
#logout:
|
||||||
|
# path: app_logout
|
||||||
|
# where to redirect after logout
|
||||||
|
# target: app_any_route
|
||||||
|
|
||||||
|
# configure the maximum login attempts
|
||||||
|
login_throttling:
|
||||||
|
limiter: app.login_rate_limiter
|
||||||
|
|
||||||
# activate different ways to authenticate
|
# activate different ways to authenticate
|
||||||
# https://symfony.com/doc/current/security.html#the-firewall
|
# https://symfony.com/doc/current/security.html#the-firewall
|
||||||
|
@ -7,7 +7,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-app}
|
POSTGRES_DB: ${POSTGRES_DB:-app}
|
||||||
# You should definitely change the password in production
|
# You should definitely change the password in production
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-Liqueur-Battalion7-Woof-Spokesman}
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-app}
|
POSTGRES_USER: ${POSTGRES_USER:-app}
|
||||||
volumes:
|
volumes:
|
||||||
- database_data:/var/lib/postgresql/data:rw
|
- database_data:/var/lib/postgresql/data:rw
|
||||||
|
37
migrations/Version20230909083131.php
Normal file
37
migrations/Version20230909083131.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20230909083131 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this up() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('CREATE TABLE domain (id INT AUTO_INCREMENT NOT NULL, domain VARCHAR(255) NOT NULL, owner_token VARCHAR(64) NOT NULL, name VARCHAR(255) NOT NULL, enabled TINYINT(1) NOT NULL, default_sort_policy VARCHAR(32) NOT NULL, updated_at DATETIME DEFAULT NULL, created_at DATETIME NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('CREATE TABLE email (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(255) NOT NULL, unsubscribe_token VARCHAR(255) NOT NULL, last_notification_sent_at DATETIME DEFAULT NULL, pending_emails INT NOT NULL, send_reply_notifications TINYINT(1) NOT NULL, send_moderator_notifications TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||||
|
$this->addSql('CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, roles LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), 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 COMMENT \'(DC2Type:datetime_immutable)\', available_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivered_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', 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');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
// this down() migration is auto-generated, please modify it to your needs
|
||||||
|
$this->addSql('DROP TABLE domain');
|
||||||
|
$this->addSql('DROP TABLE email');
|
||||||
|
$this->addSql('DROP TABLE `user`');
|
||||||
|
$this->addSql('DROP TABLE messenger_messages');
|
||||||
|
}
|
||||||
|
}
|
20
src/Controller/DashboardController.php
Normal file
20
src/Controller/DashboardController.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
|
#[IsGranted('IS_AUTHENTICATED_FULLY')]
|
||||||
|
class DashboardController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/', name: 'app_dashboard')]
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
return $this->render('dashboard/index.html.twig', [
|
||||||
|
'controller_name' => 'DashboardController',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
34
src/Controller/SecurityController.php
Normal file
34
src/Controller/SecurityController.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
|
|
||||||
|
class SecurityController extends AbstractController
|
||||||
|
{
|
||||||
|
#[Route('/login', name: 'app_login')]
|
||||||
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
|
{
|
||||||
|
// get the login error if there is one
|
||||||
|
$error = $authenticationUtils->getLastAuthenticationError();
|
||||||
|
|
||||||
|
// last username entered by the user
|
||||||
|
$lastUsername = $authenticationUtils->getLastUsername();
|
||||||
|
|
||||||
|
return $this->render('login/index.html.twig', [
|
||||||
|
'controller_name' => 'LoginController',
|
||||||
|
'last_username' => $lastUsername,
|
||||||
|
'error' => $error,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/logout', name: 'app_logout', methods: ['GET'])]
|
||||||
|
public function logout(Security $security): Response
|
||||||
|
{
|
||||||
|
return $security->logout(false);
|
||||||
|
}
|
||||||
|
}
|
129
src/Entity/Domain.php
Normal file
129
src/Entity/Domain.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\DomainRepository;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Gedmo\Mapping\Annotation\Timestampable;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: DomainRepository::class)]
|
||||||
|
class Domain
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $domain = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 64)]
|
||||||
|
private ?string $ownerToken = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $name = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?bool $enabled = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 32)]
|
||||||
|
private ?string $defaultSortPolicy = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
|
#[Timestampable(on: "update")]
|
||||||
|
private ?\DateTimeInterface $updatedAt = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
|
||||||
|
#[Timestampable(on: "create")]
|
||||||
|
private ?\DateTimeInterface $createdAt = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDomain(): ?string
|
||||||
|
{
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDomain(string $domain): static
|
||||||
|
{
|
||||||
|
$this->domain = $domain;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOwnerToken(): ?string
|
||||||
|
{
|
||||||
|
return $this->ownerToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOwnerToken(string $ownerToken): static
|
||||||
|
{
|
||||||
|
$this->ownerToken = $ownerToken;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setName(string $name): static
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEnabled(): ?bool
|
||||||
|
{
|
||||||
|
return $this->enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEnabled(bool $enabled): static
|
||||||
|
{
|
||||||
|
$this->enabled = $enabled;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultSortPolicy(): ?string
|
||||||
|
{
|
||||||
|
return $this->defaultSortPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDefaultSortPolicy(string $defaultSortPolicy): static
|
||||||
|
{
|
||||||
|
$this->defaultSortPolicy = $defaultSortPolicy;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUpdatedAt(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->updatedAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUpdatedAt(?\DateTimeInterface $updatedAt): static
|
||||||
|
{
|
||||||
|
$this->updatedAt = $updatedAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreatedAt(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCreatedAt(\DateTimeInterface $createdAt): static
|
||||||
|
{
|
||||||
|
$this->createdAt = $createdAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
111
src/Entity/Email.php
Normal file
111
src/Entity/Email.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\EmailRepository;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: EmailRepository::class)]
|
||||||
|
class Email
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $email = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private ?string $unsubscribeToken = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||||
|
private ?\DateTimeInterface $lastNotificationSentAt = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $pendingEmails = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?bool $sendReplyNotifications = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?bool $sendModeratorNotifications = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmail(): ?string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmail(string $email): static
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnsubscribeToken(): ?string
|
||||||
|
{
|
||||||
|
return $this->unsubscribeToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUnsubscribeToken(string $unsubscribeToken): static
|
||||||
|
{
|
||||||
|
$this->unsubscribeToken = $unsubscribeToken;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastNotificationSentAt(): ?\DateTimeInterface
|
||||||
|
{
|
||||||
|
return $this->lastNotificationSentAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLastNotificationSentAt(?\DateTimeInterface $lastNotificationSentAt): static
|
||||||
|
{
|
||||||
|
$this->lastNotificationSentAt = $lastNotificationSentAt;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPendingEmails(): ?int
|
||||||
|
{
|
||||||
|
return $this->pendingEmails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPendingEmails(int $pendingEmails): static
|
||||||
|
{
|
||||||
|
$this->pendingEmails = $pendingEmails;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSendReplyNotifications(): ?bool
|
||||||
|
{
|
||||||
|
return $this->sendReplyNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSendReplyNotifications(bool $sendReplyNotifications): static
|
||||||
|
{
|
||||||
|
$this->sendReplyNotifications = $sendReplyNotifications;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSendModeratorNotifications(): ?bool
|
||||||
|
{
|
||||||
|
return $this->sendModeratorNotifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSendModeratorNotifications(bool $sendModeratorNotifications): static
|
||||||
|
{
|
||||||
|
$this->sendModeratorNotifications = $sendModeratorNotifications;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
100
src/Entity/User.php
Normal file
100
src/Entity/User.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||||
|
#[ORM\Table(name: '`user`')]
|
||||||
|
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 180, unique: true)]
|
||||||
|
private ?string $email = null;
|
||||||
|
|
||||||
|
#[ORM\Column]
|
||||||
|
private array $roles = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The hashed password
|
||||||
|
*/
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?string $password = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmail(): ?string
|
||||||
|
{
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmail(string $email): static
|
||||||
|
{
|
||||||
|
$this->email = $email;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visual identifier that represents this user.
|
||||||
|
*
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function getUserIdentifier(): string
|
||||||
|
{
|
||||||
|
return (string) $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function getRoles(): array
|
||||||
|
{
|
||||||
|
$roles = $this->roles;
|
||||||
|
// guarantee every user at least has ROLE_USER
|
||||||
|
$roles[] = 'ROLE_USER';
|
||||||
|
|
||||||
|
return array_unique($roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRoles(array $roles): static
|
||||||
|
{
|
||||||
|
$this->roles = $roles;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PasswordAuthenticatedUserInterface
|
||||||
|
*/
|
||||||
|
public function getPassword(): string
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPassword(string $password): static
|
||||||
|
{
|
||||||
|
$this->password = $password;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function eraseCredentials(): void
|
||||||
|
{
|
||||||
|
// If you store any temporary, sensitive data on the user, clear it here
|
||||||
|
// $this->plainPassword = null;
|
||||||
|
}
|
||||||
|
}
|
48
src/Repository/DomainRepository.php
Normal file
48
src/Repository/DomainRepository.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Domain;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Domain>
|
||||||
|
*
|
||||||
|
* @method Domain|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method Domain|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method Domain[] findAll()
|
||||||
|
* @method Domain[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class DomainRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Domain::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return Domain[] Returns an array of Domain objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('d')
|
||||||
|
// ->andWhere('d.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('d.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?Domain
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('d')
|
||||||
|
// ->andWhere('d.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
48
src/Repository/EmailRepository.php
Normal file
48
src/Repository/EmailRepository.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\Email;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<Email>
|
||||||
|
*
|
||||||
|
* @method Email|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method Email|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method Email[] findAll()
|
||||||
|
* @method Email[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class EmailRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, Email::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return Email[] Returns an array of Email objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('e')
|
||||||
|
// ->andWhere('e.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('e.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?Email
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('e')
|
||||||
|
// ->andWhere('e.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
67
src/Repository/UserRepository.php
Normal file
67
src/Repository/UserRepository.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<User>
|
||||||
|
*
|
||||||
|
* @implements PasswordUpgraderInterface<User>
|
||||||
|
*
|
||||||
|
* @method User|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method User|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method User[] findAll()
|
||||||
|
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to upgrade (rehash) the user's password automatically over time.
|
||||||
|
*/
|
||||||
|
public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void
|
||||||
|
{
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $user::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->setPassword($newHashedPassword);
|
||||||
|
$this->getEntityManager()->persist($user);
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return User[] Returns an array of User objects
|
||||||
|
// */
|
||||||
|
// public function findByExampleField($value): array
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->orderBy('u.id', 'ASC')
|
||||||
|
// ->setMaxResults(10)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function findOneBySomeField($value): ?User
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.exampleField = :val')
|
||||||
|
// ->setParameter('val', $value)
|
||||||
|
// ->getQuery()
|
||||||
|
// ->getOneOrNullResult()
|
||||||
|
// ;
|
||||||
|
// }
|
||||||
|
}
|
21
symfony.lock
21
symfony.lock
@ -1,4 +1,13 @@
|
|||||||
{
|
{
|
||||||
|
"doctrine/annotations": {
|
||||||
|
"version": "2.0",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.10",
|
||||||
|
"ref": "64d8583af5ea57b7afa4aba4b159907f3a148b05"
|
||||||
|
}
|
||||||
|
},
|
||||||
"doctrine/doctrine-bundle": {
|
"doctrine/doctrine-bundle": {
|
||||||
"version": "2.10",
|
"version": "2.10",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
@ -95,6 +104,18 @@
|
|||||||
"src/Kernel.php"
|
"src/Kernel.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"symfony/lock": {
|
||||||
|
"version": "6.3",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "5.2",
|
||||||
|
"ref": "8e937ff2b4735d110af1770f242c1107fdab4c8e"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"config/packages/lock.yaml"
|
||||||
|
]
|
||||||
|
},
|
||||||
"symfony/mailer": {
|
"symfony/mailer": {
|
||||||
"version": "6.3",
|
"version": "6.3",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
20
templates/dashboard/index.html.twig
Normal file
20
templates/dashboard/index.html.twig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Hello DashboardController!{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<style>
|
||||||
|
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
|
||||||
|
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="example-wrapper">
|
||||||
|
<h1>Hello {{ controller_name }}! ✅</h1>
|
||||||
|
|
||||||
|
This friendly message is coming from:
|
||||||
|
<ul>
|
||||||
|
<li>Your controller at <code><a href="{{ '/home/skylar/Projects/MyComments/src/Controller/DashboardController.php'|file_link(0) }}">src/Controller/DashboardController.php</a></code></li>
|
||||||
|
<li>Your template at <code><a href="{{ '/home/skylar/Projects/MyComments/templates/dashboard/index.html.twig'|file_link(0) }}">templates/dashboard/index.html.twig</a></code></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
20
templates/login/index.html.twig
Normal file
20
templates/login/index.html.twig
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% if error %}
|
||||||
|
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ path('app_login') }}" method="post">
|
||||||
|
<label for="username">Email:</label>
|
||||||
|
<input type="text" id="username" name="_username" value="{{ last_username }}">
|
||||||
|
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input type="password" id="password" name="_password">
|
||||||
|
|
||||||
|
{# If you want to control the URL the user is redirected to on success
|
||||||
|
<input type="hidden" name="_target_path" value="/account"> #}
|
||||||
|
|
||||||
|
<button type="submit">login</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user