add captcha and top sale commodityes chart
This commit is contained in:
parent
4c5908c5c8
commit
7c58275de6
|
@ -19,7 +19,7 @@
|
|||
"melipayamak/php": "1.0.0",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"nelmio/api-doc-bundle": "^4.34",
|
||||
"nelmio/cors-bundle": "^2.4",
|
||||
"nelmio/cors-bundle": "^2.5",
|
||||
"phpdocumentor/reflection-docblock": "^5.3",
|
||||
"phpoffice/phpspreadsheet": "^1.29",
|
||||
"phpstan/phpdoc-parser": "^1.16",
|
||||
|
|
126
hesabixCore/composer.lock
generated
126
hesabixCore/composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0000709f0d53a720475e13fa5dae69ab",
|
||||
"content-hash": "66bf4d4239acf870e6cf14109284dd59",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
|
@ -1228,16 +1228,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"version": "2.20.1",
|
||||
"version": "2.20.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/orm.git",
|
||||
"reference": "e3cabade99ebccc6ba078884c1c5f250866a494e"
|
||||
"reference": "19912de9270fa6abb3d25a1a37784af6b818d534"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/e3cabade99ebccc6ba078884c1c5f250866a494e",
|
||||
"reference": "e3cabade99ebccc6ba078884c1c5f250866a494e",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/19912de9270fa6abb3d25a1a37784af6b818d534",
|
||||
"reference": "19912de9270fa6abb3d25a1a37784af6b818d534",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1324,9 +1324,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/orm/issues",
|
||||
"source": "https://github.com/doctrine/orm/tree/2.20.1"
|
||||
"source": "https://github.com/doctrine/orm/tree/2.20.2"
|
||||
},
|
||||
"time": "2024-12-19T06:48:36+00:00"
|
||||
"time": "2025-02-04T19:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/persistence",
|
||||
|
@ -1671,16 +1671,16 @@
|
|||
},
|
||||
{
|
||||
"name": "friendsofsymfony/ckeditor-bundle",
|
||||
"version": "2.5.0",
|
||||
"version": "2.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfSymfony/FOSCKEditorBundle.git",
|
||||
"reference": "9d4cd4f2db4d800164b9c3051e4bfdee21acb27f"
|
||||
"reference": "dc0f0dc1ba328e0adf5df0a37f1676b6072f46de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSCKEditorBundle/zipball/9d4cd4f2db4d800164b9c3051e4bfdee21acb27f",
|
||||
"reference": "9d4cd4f2db4d800164b9c3051e4bfdee21acb27f",
|
||||
"url": "https://api.github.com/repos/FriendsOfSymfony/FOSCKEditorBundle/zipball/dc0f0dc1ba328e0adf5df0a37f1676b6072f46de",
|
||||
"reference": "dc0f0dc1ba328e0adf5df0a37f1676b6072f46de",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1708,6 +1708,7 @@
|
|||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.41",
|
||||
"matthiasnoback/symfony-dependency-injection-test": "^4.0 || ^5.0",
|
||||
"phpunit/phpunit": "^9.6",
|
||||
"symfony/console": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0",
|
||||
"symfony/yaml": "^5.4 || ^6.0 || ^7.0"
|
||||
|
@ -1746,9 +1747,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/FriendsOfSymfony/FOSCKEditorBundle/issues",
|
||||
"source": "https://github.com/FriendsOfSymfony/FOSCKEditorBundle/tree/2.5.0"
|
||||
"source": "https://github.com/FriendsOfSymfony/FOSCKEditorBundle/tree/2.6.0"
|
||||
},
|
||||
"time": "2024-01-23T15:35:55+00:00"
|
||||
"time": "2025-01-13T15:11:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gregwar/captcha",
|
||||
|
@ -2458,16 +2459,16 @@
|
|||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.12.1",
|
||||
"version": "1.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2506,7 +2507,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2514,20 +2515,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-08T17:47:46+00:00"
|
||||
"time": "2025-02-12T12:17:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nelmio/api-doc-bundle",
|
||||
"version": "v4.36.1",
|
||||
"version": "v4.37.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nelmio/NelmioApiDocBundle.git",
|
||||
"reference": "cdc855ef8e6a811336c3a6c72fe99fbe13a78e37"
|
||||
"reference": "1497977f82d396f1dda8120434c6d29f3de683e6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/cdc855ef8e6a811336c3a6c72fe99fbe13a78e37",
|
||||
"reference": "cdc855ef8e6a811336c3a6c72fe99fbe13a78e37",
|
||||
"url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/1497977f82d396f1dda8120434c6d29f3de683e6",
|
||||
"reference": "1497977f82d396f1dda8120434c6d29f3de683e6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2628,7 +2629,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nelmio/NelmioApiDocBundle/issues",
|
||||
"source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v4.36.1"
|
||||
"source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v4.37.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -2636,7 +2637,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-19T17:01:30+00:00"
|
||||
"time": "2025-02-14T12:47:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nelmio/cors-bundle",
|
||||
|
@ -3075,20 +3076,20 @@
|
|||
},
|
||||
{
|
||||
"name": "phpoffice/phpspreadsheet",
|
||||
"version": "1.29.9",
|
||||
"version": "1.29.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||
"reference": "ffb47b639649fc9c8a6fa67977a27b756592ed85"
|
||||
"reference": "c80041b1628c4f18030407134fe88303661d4e4e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/ffb47b639649fc9c8a6fa67977a27b756592ed85",
|
||||
"reference": "ffb47b639649fc9c8a6fa67977a27b756592ed85",
|
||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/c80041b1628c4f18030407134fe88303661d4e4e",
|
||||
"reference": "c80041b1628c4f18030407134fe88303661d4e4e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/pcre": "^3.3",
|
||||
"composer/pcre": "^1||^2||^3",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
|
@ -3175,9 +3176,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.9"
|
||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.10"
|
||||
},
|
||||
"time": "2025-01-26T04:55:00+00:00"
|
||||
"time": "2025-02-08T02:56:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
|
@ -3810,31 +3811,31 @@
|
|||
},
|
||||
{
|
||||
"name": "setasign/fpdi",
|
||||
"version": "v2.6.2",
|
||||
"version": "v2.6.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Setasign/FPDI.git",
|
||||
"reference": "9e013b376939c0d4029f54150d2a16f3c67a5797"
|
||||
"reference": "67c31f5e50c93c20579ca9e23035d8c540b51941"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/9e013b376939c0d4029f54150d2a16f3c67a5797",
|
||||
"reference": "9e013b376939c0d4029f54150d2a16f3c67a5797",
|
||||
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/67c31f5e50c93c20579ca9e23035d8c540b51941",
|
||||
"reference": "67c31f5e50c93c20579ca9e23035d8c540b51941",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-zlib": "*",
|
||||
"php": "^5.6 || ^7.0 || ^8.0"
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"setasign/tfpdf": "<1.31"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5.7",
|
||||
"phpunit/phpunit": "^7",
|
||||
"setasign/fpdf": "~1.8.6",
|
||||
"setasign/tfpdf": "~1.33",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"tecnickcom/tcpdf": "~6.2"
|
||||
"tecnickcom/tcpdf": "^6.2"
|
||||
},
|
||||
"suggest": {
|
||||
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
|
||||
|
@ -3870,7 +3871,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Setasign/FPDI/issues",
|
||||
"source": "https://github.com/Setasign/FPDI/tree/v2.6.2"
|
||||
"source": "https://github.com/Setasign/FPDI/tree/v2.6.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3878,7 +3879,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-10T13:12:19+00:00"
|
||||
"time": "2025-02-05T13:22:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/apache-pack",
|
||||
|
@ -9039,20 +9040,20 @@
|
|||
},
|
||||
{
|
||||
"name": "twig/extra-bundle",
|
||||
"version": "v3.19.0",
|
||||
"version": "v3.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/twig-extra-bundle.git",
|
||||
"reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa"
|
||||
"reference": "9df5e1dbb6a68c0665ae5603f6f2c20815647876"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/9746573ca4bc1cd03a767a183faadaf84e0c31fa",
|
||||
"reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa",
|
||||
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/9df5e1dbb6a68c0665ae5603f6f2c20815647876",
|
||||
"reference": "9df5e1dbb6a68c0665ae5603f6f2c20815647876",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1.0",
|
||||
"symfony/framework-bundle": "^5.4|^6.4|^7.0",
|
||||
"symfony/twig-bundle": "^5.4|^6.4|^7.0",
|
||||
"twig/twig": "^3.2|^4.0"
|
||||
|
@ -9097,7 +9098,7 @@
|
|||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.19.0"
|
||||
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -9109,28 +9110,27 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-26T19:22:23+00:00"
|
||||
"time": "2025-02-08T09:47:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.19.0",
|
||||
"version": "v3.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e"
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d4f8c2b86374f08efc859323dbcd95c590f7124e",
|
||||
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183",
|
||||
"reference": "3468920399451a384bef53cf7996965f7cd40183",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-mbstring": "^1.3",
|
||||
"symfony/polyfill-php81": "^1.29"
|
||||
"symfony/polyfill-mbstring": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^2.0",
|
||||
|
@ -9177,7 +9177,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.19.0"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -9189,7 +9189,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-29T07:06:14+00:00"
|
||||
"time": "2025-02-13T08:34:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@ -9251,16 +9251,16 @@
|
|||
},
|
||||
{
|
||||
"name": "zircote/swagger-php",
|
||||
"version": "5.0.3",
|
||||
"version": "5.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zircote/swagger-php.git",
|
||||
"reference": "7708510b17502a416214148edaa8c9958b23b6cd"
|
||||
"reference": "2eb4005840058d8844a0bcc14403932331331068"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/7708510b17502a416214148edaa8c9958b23b6cd",
|
||||
"reference": "7708510b17502a416214148edaa8c9958b23b6cd",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/2eb4005840058d8844a0bcc14403932331331068",
|
||||
"reference": "2eb4005840058d8844a0bcc14403932331331068",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -9331,9 +9331,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/zircote/swagger-php/issues",
|
||||
"source": "https://github.com/zircote/swagger-php/tree/5.0.3"
|
||||
"source": "https://github.com/zircote/swagger-php/tree/5.0.5"
|
||||
},
|
||||
"time": "2025-01-15T21:02:43+00:00"
|
||||
"time": "2025-02-24T00:48:00+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
doctrine:
|
||||
dbal:
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
|
||||
# IMPORTANT: You MUST configure your server version,
|
||||
# either here or in the DATABASE_URL env var (see .env file)
|
||||
#server_version: '15'
|
||||
|
@ -16,6 +15,9 @@ doctrine:
|
|||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
dql:
|
||||
string_functions:
|
||||
CAST: App\Doctrine\Cast
|
||||
|
||||
when@test:
|
||||
doctrine:
|
||||
|
|
|
@ -8,10 +8,12 @@ framework:
|
|||
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
||||
# Remove or comment this section to explicitly disable session support.
|
||||
session:
|
||||
enabled: true
|
||||
handler_id: null
|
||||
cookie_secure: auto
|
||||
cookie_samesite: lax
|
||||
cookie_secure: true
|
||||
storage_factory_id: session.storage.factory.native
|
||||
cookie_lifetime: 3600 # 1 ساعت
|
||||
cookie_samesite: none # برای CORS باید Lax یا None باشه
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
# config/packages/nelmio_cors.yaml
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
origin_regex: false
|
||||
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
allow_headers: ['*']
|
||||
expose_headers: ['Link']
|
||||
allow_origin: [ '*' ] # اجازه به همه دامنهها
|
||||
allow_methods: [ 'GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ]
|
||||
allow_headers: [ '*' ] # اجازه به همه هدرها
|
||||
expose_headers: [ 'Link' ]
|
||||
allow_credentials: true # اجازه ارسال کوکیها
|
||||
max_age: 3600
|
||||
paths:
|
||||
'^/': null
|
||||
'^/':
|
||||
# اعمال تنظیمات به همه مسیرها
|
||||
allow_origin: [ '*' ]
|
||||
allow_methods: [ 'GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE' ]
|
||||
allow_headers: [ '*' ]
|
||||
expose_headers: [ 'Link' ]
|
||||
allow_credentials: true
|
||||
max_age: 3600
|
||||
|
|
|
@ -22,10 +22,13 @@ security:
|
|||
check_path: api_login
|
||||
username_path: mobile
|
||||
password_path: password
|
||||
|
||||
failure_handler: App\Security\AuthenticationFailureHandler
|
||||
form_login:
|
||||
# ...
|
||||
failure_handler: App\Security\AuthenticationFailureHandler
|
||||
custom_authenticators:
|
||||
- App\Security\ApiKeyAuthenticator
|
||||
- App\Security\ParttyAuthenticator
|
||||
- App\Security\ApiKeyAuthenticator
|
||||
- App\Security\ParttyAuthenticator
|
||||
# activate different ways to authenticate
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
|
@ -44,12 +47,12 @@ security:
|
|||
# Easy way to control access for large sections of your site
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
access_control:
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/api/acc/*, roles: ROLE_USER }
|
||||
- { path: ^/hooks/*, roles: ROLE_USER }
|
||||
- { path: ^/api/app/*, roles: ROLE_USER }
|
||||
- { path: ^/api/admin/*, roles: ROLE_ADMIN }
|
||||
- { path: ^/app/*, roles: ROLE_ADMIN }
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/api/acc/*, roles: ROLE_USER }
|
||||
- { path: ^/hooks/*, roles: ROLE_USER }
|
||||
- { path: ^/api/app/*, roles: ROLE_USER }
|
||||
- { path: ^/api/admin/*, roles: ROLE_ADMIN }
|
||||
- { path: ^/app/*, roles: ROLE_ADMIN }
|
||||
when@test:
|
||||
security:
|
||||
password_hashers:
|
||||
|
|
|
@ -12,17 +12,20 @@ parameters:
|
|||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
App\Security\AuthenticationFailureHandler:
|
||||
arguments:
|
||||
$captchaService: '@App\Service\CaptchaService'
|
||||
$requestStack: '@request_stack'
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/'
|
||||
exclude:
|
||||
- '../src/DependencyInjection/'
|
||||
- '../src/Entity/'
|
||||
- '../src/Kernel.php'
|
||||
- '../src/DependencyInjection/'
|
||||
- '../src/Entity/'
|
||||
- '../src/Kernel.php'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
|
@ -48,4 +51,4 @@ services:
|
|||
arguments: [ "@doctrine.orm.entity_manager" ]
|
||||
Printers:
|
||||
class: App\Service\Printers
|
||||
arguments: [ "@doctrine.orm.entity_manager" ]
|
||||
arguments: [ "@doctrine.orm.entity_manager" ]
|
||||
|
|
18
hesabixCore/src/Controller/CaptchaController.php
Normal file
18
hesabixCore/src/Controller/CaptchaController.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
// src/Controller/CaptchaController.php
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Service\CaptchaService;
|
||||
|
||||
class CaptchaController extends AbstractController
|
||||
{
|
||||
#[Route('/api/captcha/image', name: 'api_captcha_image', methods: ['GET'])]
|
||||
public function generateCaptchaImage(SessionInterface $session,CaptchaService $captchaService): Response
|
||||
{
|
||||
return $captchaService->createCaptchaImage($session);
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ class DashboardController extends AbstractController
|
|||
if(array_key_exists('persons',$params)) $setting->setPersons($params['persons']);
|
||||
if(array_key_exists('notif',$params)) $setting->setNotif($params['notif']);
|
||||
if(array_key_exists('sellChart',$params)) $setting->setSellChart($params['sellChart']);
|
||||
if(array_key_exists('topCommodities',$params)) $setting->setTopCommoditiesChart($params['topCommodities']);
|
||||
|
||||
$entityManagerInterface->persist($setting);
|
||||
$entityManagerInterface->flush();
|
||||
|
|
|
@ -17,6 +17,7 @@ use App\Entity\HesabdariRow;
|
|||
use App\Service\Explore;
|
||||
use App\Service\Jdate;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
@ -28,11 +29,13 @@ class ReportController extends AbstractController
|
|||
{
|
||||
private $em;
|
||||
private $provider;
|
||||
|
||||
function __construct(Provider $provider, EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->provider = $provider;
|
||||
}
|
||||
|
||||
#[Route('/api/report/person/buysell', name: 'app_report_person_buysell')]
|
||||
public function app_report_person_buysell(Provider $provider, Jdate $jdate, Access $access, Request $request, EntityManagerInterface $entityManagerInterface): JsonResponse
|
||||
{
|
||||
|
@ -215,7 +218,6 @@ class ReportController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
|
||||
$commodity = $entityManagerInterface->getRepository(Commodity::class)->findOneBy([
|
||||
'bid' => $acc['bid']->getId(),
|
||||
'code' => $params['commodity'],
|
||||
|
@ -285,4 +287,107 @@ class ReportController extends AbstractController
|
|||
}
|
||||
return $this->json($response);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/api/report/top-selling-commodities', name: 'app_report_top_selling_commodities', methods: ['POST'])]
|
||||
public function app_report_top_selling_commodities(Access $access, Explore $explore, Jdate $jdate, Request $request, EntityManagerInterface $entityManager, LoggerInterface $logger): JsonResponse
|
||||
{
|
||||
$acc = $access->hasRole('report');
|
||||
if (!$acc) {
|
||||
$acc = $access->hasRole('sell');
|
||||
if (!$acc) {
|
||||
throw $this->createAccessDeniedException('شما دسترسی لازم برای مشاهده این اطلاعات را ندارید.');
|
||||
}
|
||||
}
|
||||
|
||||
/** @var Business $business */
|
||||
$business = $acc['bid'];
|
||||
/** @var Year $year */
|
||||
$year = $acc['year'];
|
||||
|
||||
$payload = $request->getPayload();
|
||||
$period = $payload->get('period', 'year');
|
||||
$limit = (int) $payload->get('limit', 10);
|
||||
if ($limit < 3) {
|
||||
$limit = 3;
|
||||
}
|
||||
|
||||
$today = $jdate->GetTodayDate();
|
||||
list($currentYear, $currentMonth, $currentDay) = explode('/', $today);
|
||||
|
||||
switch ($period) {
|
||||
case 'today':
|
||||
$dateStart = $today;
|
||||
$dateEnd = $today;
|
||||
break;
|
||||
case 'week':
|
||||
$weekDay = (int) $jdate->jdate('w', time());
|
||||
$daysToSubtract = $weekDay;
|
||||
$dateStart = $jdate->shamsiDate(0, 0, -$daysToSubtract);
|
||||
$dateEnd = $jdate->shamsiDate(0, 0, 6 - $weekDay);
|
||||
break;
|
||||
case 'month':
|
||||
$dateStart = "$currentYear/$currentMonth/01";
|
||||
$dateEnd = "$currentYear/$currentMonth/" . $jdate->jdate('t', $jdate->jallaliToUnixTime("$currentYear/$currentMonth/01"));
|
||||
break;
|
||||
case 'year':
|
||||
default:
|
||||
$dateStart = $jdate->jdate('Y/m/d', $year->getStart());
|
||||
$dateEnd = $jdate->jdate('Y/m/d', $year->getEnd());
|
||||
break;
|
||||
}
|
||||
|
||||
$queryBuilder = $entityManager->createQueryBuilder();
|
||||
$queryBuilder
|
||||
->select('c') // Commodity
|
||||
->addSelect('SUM(CAST(hr.commdityCount AS INTEGER)) as totalCount')
|
||||
->addSelect('hr') // HesabdariRow
|
||||
->from(HesabdariRow::class, 'hr')
|
||||
->innerJoin('hr.doc', 'hd')
|
||||
->innerJoin('hr.commodity', 'c')
|
||||
->where('hd.bid = :business')
|
||||
->andWhere('hd.type = :type')
|
||||
->andWhere('hr.year = :year')
|
||||
->andWhere('hd.date BETWEEN :dateStart AND :dateEnd')
|
||||
->setParameter('business', $business)
|
||||
->setParameter('type', 'sell')
|
||||
->setParameter('year', $year)
|
||||
->setParameter('dateStart', $dateStart)
|
||||
->setParameter('dateEnd', $dateEnd)
|
||||
->groupBy('c.id, hr.id')
|
||||
->orderBy('totalCount', 'DESC')
|
||||
->setMaxResults($limit);
|
||||
|
||||
try {
|
||||
$results = $queryBuilder->getQuery()->getResult();
|
||||
$logger->info('Query executed successfully', [
|
||||
'sql' => $queryBuilder->getQuery()->getSQL(),
|
||||
'params' => $queryBuilder->getQuery()->getParameters()->toArray(),
|
||||
'results' => $results
|
||||
]);
|
||||
|
||||
if (empty($results)) {
|
||||
$logger->info('No results returned from query');
|
||||
return $this->json(['message' => 'No data found'], 200);
|
||||
}
|
||||
|
||||
$topCommodities = [];
|
||||
foreach ($results as $result) {
|
||||
// با توجه به لاگ، اندیس 0 الان HesabdariRow هست
|
||||
$row = $result[0]; // HesabdariRow
|
||||
$commodity = $row->getCommodity(); // Commodity از داخل HesabdariRow
|
||||
$totalCount = (int) $result['totalCount'];
|
||||
$topCommodities[] = $explore::ExploreCommodity($commodity, $totalCount);
|
||||
}
|
||||
|
||||
return $this->json($topCommodities);
|
||||
} catch (\Exception $e) {
|
||||
$logger->error('Error in top-selling commodities query', [
|
||||
'message' => $e->getMessage(),
|
||||
'sql' => $queryBuilder->getQuery()->getSQL(),
|
||||
'params' => $queryBuilder->getQuery()->getParameters()->toArray(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
return $this->json(['error' => 'An error occurred: ' . $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,11 @@ namespace App\Controller;
|
|||
use App\Entity\Business;
|
||||
use App\Entity\EmailHistory;
|
||||
use App\Entity\Permission;
|
||||
use App\Service\CaptchaService;
|
||||
use App\Service\Extractor;
|
||||
use App\Service\Provider;
|
||||
use App\Service\SMS;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Mime\Email;
|
||||
|
@ -18,6 +20,7 @@ use Symfony\Bundle\SecurityBundle\Security;
|
|||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
|
||||
use Symfony\Component\Security\Http\Attribute\CurrentUser;
|
||||
use App\Entity\User;
|
||||
|
@ -52,61 +55,77 @@ class UserController extends AbstractController
|
|||
return substr(str_shuffle(str_repeat($x = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length / strlen($x)))), 1, $length);
|
||||
}
|
||||
|
||||
#[Route('/api/user/login', name: 'api_login')]
|
||||
public function api_login(TranslatorInterface $translatorInterface, Extractor $extractor, Request $request, #[CurrentUser] ?User $user, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
#[Route('/api/user/login', name: 'api_login', methods: ['POST'])]
|
||||
public function api_login(
|
||||
TranslatorInterface $translatorInterface,
|
||||
Extractor $extractor,
|
||||
Request $request,
|
||||
CaptchaService $captchaService,
|
||||
#[CurrentUser] ?User $user,
|
||||
EntityManagerInterface $entityManager
|
||||
): Response {
|
||||
$params = $request->getPayload()->all();
|
||||
if (array_key_exists('standard', $params)) {
|
||||
if (null === $user) {
|
||||
$captchaAnswer = $params['captcha_answer'] ?? '';
|
||||
$attemptKey = 'login_attempts';
|
||||
|
||||
// بررسی نیاز به کپچا
|
||||
$captchaRequired = $captchaService->isCaptchaRequired($attemptKey);
|
||||
if ($captchaRequired) {
|
||||
if (!$captchaService->validateCaptcha($captchaAnswer)) {
|
||||
return $this->json($extractor->operationFail(
|
||||
$translatorInterface->trans('login_fail'),
|
||||
empty($captchaAnswer) ? 'کپچا لازم است' : 'کپچا اشتباه است',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
if ($user->isActive() == false) {
|
||||
return $this->json($extractor->operationFail(
|
||||
'حساب کاربری شما فعال نیست. لطفا با پشتیبانی تماس بگیرید'
|
||||
,
|
||||
506,
|
||||
[
|
||||
'user' => $user->getUserIdentifier(),
|
||||
'active' => $user->isActive(),
|
||||
]
|
||||
));
|
||||
}
|
||||
$token = new UserToken();
|
||||
$token->setUser($user);
|
||||
$token->setToken($this->RandomString(254));
|
||||
$token->setTokenID($this->RandomString(254));
|
||||
$entityManager->persist($token);
|
||||
$entityManager->flush();
|
||||
return $this->json($extractor->operationSuccess([
|
||||
'user' => $user->getUserIdentifier(),
|
||||
'token' => $token->getToken(),
|
||||
'tokenID' => $token->getTokenID(),
|
||||
'active' => $user->isActive(),
|
||||
]));
|
||||
} else {
|
||||
if (null === $user) {
|
||||
return $this->json([
|
||||
'message' => 'missing credentials',
|
||||
], Response::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
$token = new UserToken();
|
||||
$token->setUser($user);
|
||||
$token->setToken($this->RandomString(254));
|
||||
$token->setTokenID($this->RandomString(254));
|
||||
$entityManager->persist($token);
|
||||
$entityManager->flush();
|
||||
return $this->json([
|
||||
'user' => $user->getUserIdentifier(),
|
||||
'token' => $token->getToken(),
|
||||
'tokenID' => $token->getTokenID(),
|
||||
'active' => $user->isActive(),
|
||||
]);
|
||||
}
|
||||
|
||||
// چون #[CurrentUser] فقط در صورت احراز هویت موفق کاربر رو برمیگردونه،
|
||||
// اینجا فقط شرایط بعد از احراز هویت موفق بررسی میشه
|
||||
if (null === $user) {
|
||||
// این خط عملاً اجرا نمیشه چون Security Bundle شکست رو مدیریت میکنه
|
||||
// اما برای اطمینان نگهش داشتم
|
||||
$captchaService->incrementAttempts($attemptKey);
|
||||
return $this->json($extractor->operationFail(
|
||||
$translatorInterface->trans('login_fail'),
|
||||
400,
|
||||
['captcha_required' => $captchaService->isCaptchaRequired($attemptKey)]
|
||||
));
|
||||
}
|
||||
|
||||
// بررسی وضعیت کاربر
|
||||
if ($user->isActive() == false) {
|
||||
$captchaService->incrementAttempts($attemptKey);
|
||||
return $this->json($extractor->operationFail(
|
||||
'حساب کاربری شما فعال نیست. لطفا با پشتیبانی تماس بگیرید',
|
||||
506,
|
||||
[
|
||||
'user' => $user->getUserIdentifier(),
|
||||
'active' => $user->isActive(),
|
||||
'captcha_required' => $captchaService->isCaptchaRequired($attemptKey)
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
// ورود موفق
|
||||
$token = new UserToken();
|
||||
$token->setUser($user);
|
||||
$token->setToken($this->RandomString(254));
|
||||
$token->setTokenID($this->RandomString(254));
|
||||
$entityManager->persist($token);
|
||||
$entityManager->flush();
|
||||
|
||||
$captchaService->resetAttempts($attemptKey);
|
||||
return $this->json($extractor->operationSuccess([
|
||||
'user' => $user->getUserIdentifier(),
|
||||
'token' => $token->getToken(),
|
||||
'tokenID' => $token->getTokenID(),
|
||||
'active' => $user->isActive(),
|
||||
'captcha_required' => false
|
||||
]));
|
||||
}
|
||||
|
||||
|
||||
#[Route('/api/user/has/role/{id}', name: 'api_user_has_role')]
|
||||
public function api_user_has_role(Extractor $extractor, #[CurrentUser] ?User $user, EntityManagerInterface $entityManager, $id): Response
|
||||
{
|
||||
|
@ -279,23 +298,51 @@ class UserController extends AbstractController
|
|||
));
|
||||
}
|
||||
|
||||
#[Route('/api/user/register', name: 'api_user_register')]
|
||||
public function api_user_register(Extractor $extractor, registryMGR $registryMGR, SMS $SMS, MailerInterface $mailer, Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
#[Route('/api/user/register', name: 'api_user_register', methods: ['POST'])]
|
||||
public function api_user_register(
|
||||
Extractor $extractor,
|
||||
registryMGR $registryMGR,
|
||||
SMS $SMS,
|
||||
MailerInterface $mailer,
|
||||
Request $request,
|
||||
UserPasswordHasherInterface $userPasswordHasher,
|
||||
EntityManagerInterface $entityManager,
|
||||
CaptchaService $captchaService // اضافه کردن به آرگومانهای متد
|
||||
): Response {
|
||||
$params = [];
|
||||
if ($content = $request->getContent()) {
|
||||
$params = json_decode($content, true);
|
||||
}
|
||||
if (array_key_exists('name', $params) && array_key_exists('email', $params) && array_key_exists('mobile', $params) && array_key_exists('password', $params)) {
|
||||
|
||||
// همیشه کپچا رو چک میکنیم
|
||||
$captchaAnswer = $params['captcha_answer'] ?? '';
|
||||
if (!$captchaService->validateCaptcha($captchaAnswer)) {
|
||||
return $this->json($extractor->operationFail(
|
||||
empty($captchaAnswer) ? 'کپچا لازم است' : 'کپچا اشتباه است',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
|
||||
// ادامه منطق عضویت
|
||||
if (
|
||||
array_key_exists('name', $params) && array_key_exists('email', $params) &&
|
||||
array_key_exists('mobile', $params) && array_key_exists('password', $params)
|
||||
) {
|
||||
if ($entityManager->getRepository(User::class)->findOneBy(['email' => trim($params['email'])])) {
|
||||
return $this->json($extractor->operationFail(
|
||||
'پست الکترونیکی وارد شده قبلا ثبت شده است'
|
||||
'پست الکترونیکی وارد شده قبلا ثبت شده است',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
} elseif ($entityManager->getRepository(User::class)->findOneBy(['mobile' => trim($params['mobile'])])) {
|
||||
return $this->json($extractor->operationFail(
|
||||
'شماره تلفن وارد شده قبلا ثبت شده است'
|
||||
'شماره تلفن وارد شده قبلا ثبت شده است',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
|
||||
$user = new User();
|
||||
$user->setEmail($params['email']);
|
||||
$user->setRoles(['ROLE_USER']);
|
||||
|
@ -313,11 +360,13 @@ class UserController extends AbstractController
|
|||
$user->setActive(false);
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
$SMS->send(
|
||||
[$user->getVerifyCode()],
|
||||
$registryMGR->get('sms', 'f2a'),
|
||||
$user->getMobile()
|
||||
);
|
||||
|
||||
try {
|
||||
$email = (new Email())
|
||||
->to($user->getEmail())
|
||||
|
@ -331,16 +380,22 @@ class UserController extends AbstractController
|
|||
|
||||
$mailer->send($email);
|
||||
} catch (Exception $exception) {
|
||||
// خطای ارسال ایمیل رو میتونید لاگ کنید، فعلاً نادیده میگیره
|
||||
}
|
||||
|
||||
return $this->json($extractor->operationSuccess([
|
||||
'id' => $user->getId()
|
||||
]));
|
||||
}
|
||||
|
||||
return $this->json($extractor->operationFail(
|
||||
'تمام موارد لازم را وارد کنید.'
|
||||
'تمام موارد لازم را وارد کنید.',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
#[Route('/api/user/active/code/info/{id}', name: 'api_user_active_code_info')]
|
||||
public function api_user_active_code_info(registryMGR $registryMGR, MailerInterface $mailer, SMS $SMS, string $id, #[CurrentUser] ?User $user, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, Request $request): Response
|
||||
{
|
||||
|
@ -479,35 +534,61 @@ class UserController extends AbstractController
|
|||
}
|
||||
return $this->json($extractor->operationFail('کد ارسالی اشتباه است.'));
|
||||
}
|
||||
#[Route('/api/user/forget/password/send-code', name: 'api_user_forget_password_send_code')]
|
||||
public function api_user_forget_password_send_code(Extractor $extractor, registryMGR $registryMGR, #[CurrentUser] ?User $user, SMS $SMS, MailerInterface $mailer, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, Request $request): Response
|
||||
{
|
||||
|
||||
#[Route('/api/user/forget/password/send-code', name: 'api_user_forget_password_send_code', methods: ['POST'])]
|
||||
public function api_user_forget_password_send_code(
|
||||
Extractor $extractor,
|
||||
registryMGR $registryMGR,
|
||||
#[CurrentUser] ?User $user,
|
||||
SMS $SMS,
|
||||
MailerInterface $mailer,
|
||||
UserPasswordHasherInterface $userPasswordHasher,
|
||||
EntityManagerInterface $entityManager,
|
||||
Request $request,
|
||||
CaptchaService $captchaService
|
||||
): Response {
|
||||
$params = [];
|
||||
if ($content = $request->getContent()) {
|
||||
$params = json_decode($content, true);
|
||||
}
|
||||
|
||||
// همیشه کپچا رو چک میکنیم
|
||||
$captchaAnswer = $params['captcha_answer'] ?? '';
|
||||
if (!$captchaService->validateCaptcha($captchaAnswer)) {
|
||||
return $this->json($extractor->operationFail(
|
||||
empty($captchaAnswer) ? 'کپچا لازم است' : 'کپچا اشتباه است',
|
||||
400,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
|
||||
// ادامه منطق بازیابی
|
||||
if (!array_key_exists('mobile', $params)) {
|
||||
return $this->json($extractor->paramsNotSend());
|
||||
}
|
||||
|
||||
$user = $entityManager->getRepository(User::class)->findOneBy(['mobile' => $params['mobile']]);
|
||||
if (!$user) {
|
||||
return $this->json(data: $extractor->operationFail(
|
||||
return $this->json($extractor->operationFail(
|
||||
'کاربری با شماره تلفن وارد شده یافت نشد.',
|
||||
404
|
||||
404,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
if ($user->getVerifyCodeTime() > time()) {
|
||||
return $this->json(data: $extractor->operationFail(
|
||||
'کد بازیابی رمز عبور اخیرا ارسال شده است.لطفا چند دقیقه دیگر مجددا درخواست خود را ارسال نمایید.',
|
||||
600
|
||||
return $this->json($extractor->operationFail(
|
||||
'کد بازیابی رمز عبور اخیرا ارسال شده است. لطفا چند دقیقه دیگر مجددا درخواست خود را ارسال نمایید.',
|
||||
600,
|
||||
['captcha_required' => true]
|
||||
));
|
||||
}
|
||||
|
||||
$user->setVerifyCode($this->RandomString(6, true));
|
||||
$user->setVerifyCodeTime(time() + 300);
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
//send sms and email
|
||||
|
||||
// ارسال SMS و ایمیل
|
||||
$SMS->send(
|
||||
[$user->getVerifyCode()],
|
||||
$registryMGR->get('sms', 'recPassword'),
|
||||
|
@ -524,10 +605,12 @@ class UserController extends AbstractController
|
|||
);
|
||||
|
||||
$mailer->send($email);
|
||||
|
||||
return $this->json($extractor->operationSuccess([
|
||||
'id' => $user->getId(),
|
||||
]));
|
||||
}
|
||||
|
||||
#[Route('/api/user/save/mobile-number', name: 'api_user_save_mobile_number')]
|
||||
public function api_user_save_mobile_number(MailerInterface $mailer, SMS $SMS, #[CurrentUser] ?User $user, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager, Request $request): Response
|
||||
{
|
||||
|
|
28
hesabixCore/src/Doctrine/Cast.php
Normal file
28
hesabixCore/src/Doctrine/Cast.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
namespace App\Doctrine;
|
||||
|
||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||
use Doctrine\ORM\Query\Lexer;
|
||||
use Doctrine\ORM\Query\Parser;
|
||||
use Doctrine\ORM\Query\SqlWalker;
|
||||
|
||||
class Cast extends FunctionNode
|
||||
{
|
||||
private $expression;
|
||||
|
||||
public function parse(Parser $parser)
|
||||
{
|
||||
$parser->match(Lexer::T_IDENTIFIER); // CAST
|
||||
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||
$this->expression = $parser->ArithmeticExpression();
|
||||
$parser->match(Lexer::T_AS);
|
||||
$parser->match(Lexer::T_IDENTIFIER); // INTEGER یا هر نوع دیگه
|
||||
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||
}
|
||||
|
||||
public function getSql(SqlWalker $sqlWalker)
|
||||
{
|
||||
// به جای استفاده از $this->type، مستقیماً SIGNED رو میذاریم
|
||||
return 'CAST(' . $sqlWalker->walkArithmeticPrimary($this->expression) . ' AS SIGNED)';
|
||||
}
|
||||
}
|
|
@ -51,6 +51,9 @@ class DashboardSettings
|
|||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $sellChart = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $topCommoditiesChart = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
|
@ -199,4 +202,16 @@ class DashboardSettings
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isTopCommoditiesChart(): ?bool
|
||||
{
|
||||
return $this->topCommoditiesChart;
|
||||
}
|
||||
|
||||
public function setTopCommoditiesChart(?bool $topCommoditiesChart): static
|
||||
{
|
||||
$this->topCommoditiesChart = $topCommoditiesChart;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
// src/EventListener/AuthenticationFailureListener.php
|
||||
namespace App\EventListener;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
use Symfony\Component\Security\Http\Event\AuthenticationFailureEvent;
|
||||
use App\Service\CaptchaService;
|
||||
|
||||
class AuthenticationFailureListener
|
||||
{
|
||||
private CaptchaService $captchaService;
|
||||
private SessionInterface $session;
|
||||
|
||||
public function __construct(CaptchaService $captchaService, SessionInterface $session)
|
||||
{
|
||||
$this->captchaService = $captchaService;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(AuthenticationFailureEvent $event): void
|
||||
{
|
||||
$attemptKey = 'login_attempts';
|
||||
$this->captchaService->incrementAttempts($this->session, $attemptKey);
|
||||
}
|
||||
}
|
40
hesabixCore/src/Security/AuthenticationFailureHandler.php
Normal file
40
hesabixCore/src/Security/AuthenticationFailureHandler.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
// src/Security/AuthenticationFailureHandler.php
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use App\Service\CaptchaService;
|
||||
|
||||
class AuthenticationFailureHandler implements AuthenticationFailureHandlerInterface
|
||||
{
|
||||
private CaptchaService $captchaService;
|
||||
private RequestStack $requestStack;
|
||||
|
||||
public function __construct(CaptchaService $captchaService, RequestStack $requestStack)
|
||||
{
|
||||
$this->captchaService = $captchaService;
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): JsonResponse
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
$attemptKey = 'login_attempts';
|
||||
$this->captchaService->incrementAttempts($attemptKey);
|
||||
|
||||
$attempts = $session->get($attemptKey, 0);
|
||||
$sessionId = $session->getId(); // برای چک کردن اینکه سشن ثابت میمونه یا نه
|
||||
|
||||
return new JsonResponse([
|
||||
'error' => 'احراز هویت نامعتبر می باشد.',
|
||||
'captcha_required' => $this->captchaService->isCaptchaRequired($attemptKey),
|
||||
'attempts' => $attempts,
|
||||
'last_attempt_time' => $session->get($attemptKey . '_time', 0),
|
||||
'session_id' => $sessionId // برای دیباگ
|
||||
], 401);
|
||||
}
|
||||
}
|
125
hesabixCore/src/Service/CaptchaService.php
Normal file
125
hesabixCore/src/Service/CaptchaService.php
Normal file
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
// src/Service/CaptchaService.php
|
||||
namespace App\Service;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CaptchaService
|
||||
{
|
||||
private RequestStack $requestStack;
|
||||
|
||||
public function __construct(RequestStack $requestStack)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
}
|
||||
|
||||
public function createCaptchaImage(): Response
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
|
||||
// تولید کپچا که با صفر شروع نشه
|
||||
$firstDigit = rand(1, 9); // رقم اول بین 1 تا 9
|
||||
$remainingDigits = str_pad(rand(0, 99999), 5, '0', STR_PAD_LEFT); // ۵ رقم بعدی
|
||||
$captchaCode = $firstDigit . $remainingDigits; // ترکیب به صورت ۶ رقمی
|
||||
|
||||
$persianNumbers = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
||||
$englishNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
$captchaCodePersian = str_replace($englishNumbers, $persianNumbers, $captchaCode);
|
||||
|
||||
$session->set('captcha_code', $captchaCode);
|
||||
|
||||
$image = imagecreatetruecolor(200, 80);
|
||||
$backgroundColor = imagecolorallocate($image, 255, 255, 255);
|
||||
$textColor = imagecolorallocate($image, 0, 0, 0);
|
||||
imagefill($image, 0, 0, $backgroundColor);
|
||||
|
||||
$fontPath = __DIR__ . '/../Fonts/Vazirmatn-Black.ttf';
|
||||
imagettftext($image, 20, rand(-10, 10), 40, 50, $textColor, $fontPath, $captchaCodePersian);
|
||||
|
||||
$lineColor1 = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
||||
$lineColor2 = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
||||
imageline($image, rand(0, 50), rand(0, 80), rand(150, 200), rand(0, 80), $lineColor1);
|
||||
imageline($image, rand(0, 50), rand(0, 80), rand(150, 200), rand(0, 80), $lineColor2);
|
||||
|
||||
$circleColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
||||
imageellipse($image, rand(20, 180), rand(10, 70), rand(20, 50), rand(20, 50), $circleColor);
|
||||
|
||||
$squareColor = imagecolorallocate($image, rand(0, 255), rand(0, 255), rand(0, 255));
|
||||
$squareX = rand(20, 160);
|
||||
$squareY = rand(10, 40);
|
||||
$squareSize = rand(20, 40);
|
||||
imagerectangle($image, $squareX, $squareY, $squareX + $squareSize, $squareY + $squareSize, $squareColor);
|
||||
|
||||
imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
|
||||
|
||||
$wavedImage = imagecreatetruecolor(200, 80);
|
||||
imagefill($wavedImage, 0, 0, $backgroundColor);
|
||||
for ($x = 0; $x < 200; $x++) {
|
||||
for ($y = 0; $y < 80; $y++) {
|
||||
$newX = $x + sin($y / 10) * 5;
|
||||
$newY = $y + cos($x / 10) * 5;
|
||||
if ($newX >= 0 && $newX < 200 && $newY >= 0 && $newY < 80) {
|
||||
$color = imagecolorat($image, $x, $y);
|
||||
imagesetpixel($wavedImage, (int)$newX, (int)$newY, $color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
imagepng($wavedImage);
|
||||
$imageData = ob_get_clean();
|
||||
imagedestroy($image);
|
||||
imagedestroy($wavedImage);
|
||||
|
||||
return new Response($imageData, 200, ['Content-Type' => 'image/png']);
|
||||
}
|
||||
|
||||
public function isCaptchaRequired(string $attemptKey): bool
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
$attempts = $session->get($attemptKey, 0);
|
||||
$lastAttemptTime = $session->get($attemptKey . '_time', 0);
|
||||
$currentTime = time();
|
||||
$halfHour = 30 * 60;
|
||||
|
||||
if (($currentTime - $lastAttemptTime) > $halfHour) {
|
||||
$session->set($attemptKey, 0);
|
||||
$session->set($attemptKey . '_time', $currentTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $attempts >= 3;
|
||||
}
|
||||
|
||||
public function validateCaptcha(string $captchaAnswer): bool
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
if (empty($captchaAnswer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$storedCode = $session->get('captcha_code');
|
||||
if ($captchaAnswer === $storedCode) {
|
||||
$session->remove('captcha_code');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function incrementAttempts(string $attemptKey): void
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
$attempts = $session->get($attemptKey, 0) + 1;
|
||||
$session->set($attemptKey, $attempts);
|
||||
$session->set($attemptKey . '_time', time());
|
||||
}
|
||||
|
||||
public function resetAttempts(string $attemptKey): void
|
||||
{
|
||||
$session = $this->requestStack->getSession();
|
||||
$session->set($attemptKey, 0);
|
||||
$session->set($attemptKey . '_time', time());
|
||||
}
|
||||
}
|
|
@ -584,7 +584,10 @@ class Explore
|
|||
'persons' => $item->isPersons(),
|
||||
'notif' => $item->isNotif(),
|
||||
'sellChart' => $item->isSellChart(),
|
||||
'topCommodities' => $item->isTopCommoditiesChart(),
|
||||
];
|
||||
if ($result['topCommodities'] === null)
|
||||
$result['topCommodities'] = true;
|
||||
if ($result['banks'] === null)
|
||||
$result['banks'] = true;
|
||||
if ($result['buys'] === null)
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
1
public_html/bundles/nelmioapidoc/stoplight/styles.min.css
vendored
Normal file
1
public_html/bundles/nelmioapidoc/stoplight/styles.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public_html/bundles/nelmioapidoc/stoplight/web-components.min.js
vendored
Normal file
2
public_html/bundles/nelmioapidoc/stoplight/web-components.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
use App\Kernel;
|
||||
require_once dirname(__DIR__).'/hesabixCore/vendor/autoload_runtime.php';
|
||||
header("Access-Control-Allow-Credentials: true");
|
||||
return function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
Loading…
Reference in a new issue