2
.github/workflows/testing.yaml
vendored
2
.github/workflows/testing.yaml
vendored
@@ -93,7 +93,6 @@ jobs:
|
||||
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
|
||||
APP_ENV: test
|
||||
MAILER_URL: null://localhost
|
||||
TEST_WITH_BUNDLES: 1
|
||||
|
||||
- name: Full test-suite with coverage
|
||||
if: matrix.php == '8.2'
|
||||
@@ -102,7 +101,6 @@ jobs:
|
||||
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
|
||||
APP_ENV: dev
|
||||
MAILER_URL: null://localhost
|
||||
TEST_WITH_BUNDLES: 1
|
||||
|
||||
- name: Upload code coverage
|
||||
if: matrix.php == '8.2'
|
||||
|
||||
280
composer.lock
generated
280
composer.lock
generated
@@ -1387,16 +1387,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"version": "2.19.4",
|
||||
"version": "2.19.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/orm.git",
|
||||
"reference": "b27489348658cd718d18005de37b94f7f8561467"
|
||||
"reference": "94986af28452da42a46a4489d1c958a2e5d710e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/b27489348658cd718d18005de37b94f7f8561467",
|
||||
"reference": "b27489348658cd718d18005de37b94f7f8561467",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/94986af28452da42a46a4489d1c958a2e5d710e5",
|
||||
"reference": "94986af28452da42a46a4489d1c958a2e5d710e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1482,9 +1482,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/orm/issues",
|
||||
"source": "https://github.com/doctrine/orm/tree/2.19.4"
|
||||
"source": "https://github.com/doctrine/orm/tree/2.19.5"
|
||||
},
|
||||
"time": "2024-04-15T13:11:10+00:00"
|
||||
"time": "2024-04-30T06:49:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/persistence",
|
||||
@@ -1586,23 +1586,26 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/sql-formatter",
|
||||
"version": "1.2.0",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/sql-formatter.git",
|
||||
"reference": "a321d114e0a18e6497f8a2cd6f890e000cc17ecc"
|
||||
"reference": "d1ac84aef745c69ea034929eb6d65a6908b675cc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/a321d114e0a18e6497f8a2cd6f890e000cc17ecc",
|
||||
"reference": "a321d114e0a18e6497f8a2cd6f890e000cc17ecc",
|
||||
"url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d1ac84aef745c69ea034929eb6d65a6908b675cc",
|
||||
"reference": "d1ac84aef745c69ea034929eb6d65a6908b675cc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.4"
|
||||
"doctrine/coding-standard": "^12",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"vimeo/psalm": "^5.24"
|
||||
},
|
||||
"bin": [
|
||||
"bin/sql-formatter"
|
||||
@@ -1632,9 +1635,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/sql-formatter/issues",
|
||||
"source": "https://github.com/doctrine/sql-formatter/tree/1.2.0"
|
||||
"source": "https://github.com/doctrine/sql-formatter/tree/1.4.0"
|
||||
},
|
||||
"time": "2023-08-16T21:49:04+00:00"
|
||||
"time": "2024-05-08T08:12:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "egulias/email-validator",
|
||||
@@ -3446,16 +3449,16 @@
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v2.6.3",
|
||||
"version": "v2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938"
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"reference": "58c3f47f650c94ec05a151692652a868995d2938",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3509,7 +3512,7 @@
|
||||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2022-06-14T06:56:20+00:00"
|
||||
"time": "2024-05-08T12:18:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
@@ -4005,16 +4008,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpdoc-parser",
|
||||
"version": "1.28.0",
|
||||
"version": "1.29.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||
"reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb"
|
||||
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb",
|
||||
"reference": "cd06d6b1a1b3c75b0b83f97577869fd85a3cd4fb",
|
||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc",
|
||||
"reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4046,9 +4049,9 @@
|
||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.28.0"
|
||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0"
|
||||
},
|
||||
"time": "2024-04-03T18:51:33+00:00"
|
||||
"time": "2024-05-06T12:04:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -4304,20 +4307,20 @@
|
||||
},
|
||||
{
|
||||
"name": "psr/http-factory",
|
||||
"version": "1.0.2",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-factory.git",
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35"
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
|
||||
"reference": "e616d01114759c4c489f93b099585439f795fe35",
|
||||
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0",
|
||||
"php": ">=7.1",
|
||||
"psr/http-message": "^1.0 || ^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -4341,7 +4344,7 @@
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for PSR-7 HTTP message factories",
|
||||
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
|
||||
"keywords": [
|
||||
"factory",
|
||||
"http",
|
||||
@@ -4353,9 +4356,9 @@
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
|
||||
"source": "https://github.com/php-fig/http-factory"
|
||||
},
|
||||
"time": "2023-04-10T20:10:41+00:00"
|
||||
"time": "2024-04-15T12:06:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
@@ -5040,16 +5043,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache-contracts",
|
||||
"version": "v3.4.2",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/cache-contracts.git",
|
||||
"reference": "2c9db6509a1b21dad229606897639d3284f54b2a"
|
||||
"reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/2c9db6509a1b21dad229606897639d3284f54b2a",
|
||||
"reference": "2c9db6509a1b21dad229606897639d3284f54b2a",
|
||||
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197",
|
||||
"reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5059,7 +5062,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -5096,7 +5099,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/cache-contracts/tree/v3.4.2"
|
||||
"source": "https://github.com/symfony/cache-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5112,7 +5115,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-23T14:51:35+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/clock",
|
||||
@@ -5505,16 +5508,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.4.0",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
|
||||
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
|
||||
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
|
||||
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5523,7 +5526,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -5552,7 +5555,7 @@
|
||||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5568,7 +5571,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-23T14:45:45+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/doctrine-bridge",
|
||||
@@ -5909,16 +5912,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
"version": "v3.4.2",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
||||
"reference": "4e64b49bf370ade88e567de29465762e316e4224"
|
||||
"reference": "8f93aec25d41b72493c6ddff14e916177c9efc50"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224",
|
||||
"reference": "4e64b49bf370ade88e567de29465762e316e4224",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50",
|
||||
"reference": "8f93aec25d41b72493c6ddff14e916177c9efc50",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5928,7 +5931,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -5965,7 +5968,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2"
|
||||
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5981,7 +5984,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-23T14:51:35+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/expression-language",
|
||||
@@ -6580,16 +6583,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
"version": "v3.4.2",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client-contracts.git",
|
||||
"reference": "b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e"
|
||||
"reference": "20414d96f391677bf80078aa55baece78b82647d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e",
|
||||
"reference": "b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d",
|
||||
"reference": "20414d96f391677bf80078aa55baece78b82647d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6598,7 +6601,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -6638,7 +6641,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.4.2"
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6654,7 +6657,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-01T18:51:09+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
@@ -8706,21 +8709,22 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.4.2",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "11bbf19a0fb7b36345861e85c5768844c552906e"
|
||||
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e",
|
||||
"reference": "11bbf19a0fb7b36345861e85c5768844c552906e",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
|
||||
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"psr/container": "^1.1|^2.0"
|
||||
"psr/container": "^1.1|^2.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-psr": "<1.1|>=2"
|
||||
@@ -8728,7 +8732,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -8768,7 +8772,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.4.2"
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8784,7 +8788,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-19T21:51:00+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/stopwatch",
|
||||
@@ -9031,16 +9035,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation-contracts",
|
||||
"version": "v3.4.2",
|
||||
"version": "v3.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation-contracts.git",
|
||||
"reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b"
|
||||
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/43810bdb2ddb5400e5c5e778e27b210a0ca83b6b",
|
||||
"reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b",
|
||||
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9049,7 +9053,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.4-dev"
|
||||
"dev-main": "3.5-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
@@ -9089,7 +9093,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.4.2"
|
||||
"source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9105,7 +9109,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-23T14:51:35+00:00"
|
||||
"time": "2024-04-18T09:32:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/twig-bridge",
|
||||
@@ -9756,16 +9760,16 @@
|
||||
},
|
||||
{
|
||||
"name": "twig/cssinliner-extra",
|
||||
"version": "v3.9.0",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/cssinliner-extra.git",
|
||||
"reference": "419e3e98431da91e8051ffdb447725d10935285d"
|
||||
"reference": "10e88e9a887b646c58e3d670383208f15295dd22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/cssinliner-extra/zipball/419e3e98431da91e8051ffdb447725d10935285d",
|
||||
"reference": "419e3e98431da91e8051ffdb447725d10935285d",
|
||||
"url": "https://api.github.com/repos/twigphp/cssinliner-extra/zipball/10e88e9a887b646c58e3d670383208f15295dd22",
|
||||
"reference": "10e88e9a887b646c58e3d670383208f15295dd22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9809,7 +9813,7 @@
|
||||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/cssinliner-extra/tree/v3.9.0"
|
||||
"source": "https://github.com/twigphp/cssinliner-extra/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9821,20 +9825,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-10T19:34:32+00:00"
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/extra-bundle",
|
||||
"version": "v3.9.3",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/twig-extra-bundle.git",
|
||||
"reference": "ef6869adf1fdab66f7e495771a7ba01496ffc0d5"
|
||||
"reference": "cdc6e23aeb7f4953c1039568c3439aab60c56454"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/ef6869adf1fdab66f7e495771a7ba01496ffc0d5",
|
||||
"reference": "ef6869adf1fdab66f7e495771a7ba01496ffc0d5",
|
||||
"url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/cdc6e23aeb7f4953c1039568c3439aab60c56454",
|
||||
"reference": "cdc6e23aeb7f4953c1039568c3439aab60c56454",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9883,7 +9887,7 @@
|
||||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.9.3"
|
||||
"source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9895,20 +9899,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T09:24:21+00:00"
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/inky-extra",
|
||||
"version": "v3.9.0",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/inky-extra.git",
|
||||
"reference": "95e489a56feaacff255deb1ffd9c7e2956985755"
|
||||
"reference": "adfcc3b2becc09e909d30b813cde17351ac82958"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/inky-extra/zipball/95e489a56feaacff255deb1ffd9c7e2956985755",
|
||||
"reference": "95e489a56feaacff255deb1ffd9c7e2956985755",
|
||||
"url": "https://api.github.com/repos/twigphp/inky-extra/zipball/adfcc3b2becc09e909d30b813cde17351ac82958",
|
||||
"reference": "adfcc3b2becc09e909d30b813cde17351ac82958",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -9953,7 +9957,7 @@
|
||||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/inky-extra/tree/v3.9.0"
|
||||
"source": "https://github.com/twigphp/inky-extra/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -9965,26 +9969,26 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-10T19:34:32+00:00"
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/intl-extra",
|
||||
"version": "v3.9.2",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/intl-extra.git",
|
||||
"reference": "39865e5d13165016a8e7ab8cc648ad2f7aa4b639"
|
||||
"reference": "693f6beb8ca91fc6323e01b3addf983812f65c93"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/intl-extra/zipball/39865e5d13165016a8e7ab8cc648ad2f7aa4b639",
|
||||
"reference": "39865e5d13165016a8e7ab8cc648ad2f7aa4b639",
|
||||
"url": "https://api.github.com/repos/twigphp/intl-extra/zipball/693f6beb8ca91fc6323e01b3addf983812f65c93",
|
||||
"reference": "693f6beb8ca91fc6323e01b3addf983812f65c93",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"symfony/intl": "^5.4|^6.4|^7.0",
|
||||
"twig/twig": "^3.9"
|
||||
"twig/twig": "^3.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^6.4|^7.0"
|
||||
@@ -10017,7 +10021,7 @@
|
||||
"twig"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/intl-extra/tree/v3.9.2"
|
||||
"source": "https://github.com/twigphp/intl-extra/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10029,20 +10033,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-17T12:41:53+00:00"
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/string-extra",
|
||||
"version": "v3.9.0",
|
||||
"version": "v3.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/string-extra.git",
|
||||
"reference": "5ff1c41366aa003d45f6e2707c5d698c1b37ff99"
|
||||
"reference": "cd76ed8ae081bcd4fddf549e92e20c5df76c358a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/string-extra/zipball/5ff1c41366aa003d45f6e2707c5d698c1b37ff99",
|
||||
"reference": "5ff1c41366aa003d45f6e2707c5d698c1b37ff99",
|
||||
"url": "https://api.github.com/repos/twigphp/string-extra/zipball/cd76ed8ae081bcd4fddf549e92e20c5df76c358a",
|
||||
"reference": "cd76ed8ae081bcd4fddf549e92e20c5df76c358a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10084,7 +10088,7 @@
|
||||
"unicode"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/twigphp/string-extra/tree/v3.9.0"
|
||||
"source": "https://github.com/twigphp/string-extra/tree/v3.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10096,20 +10100,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-10T08:52:03+00:00"
|
||||
"time": "2024-05-11T07:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v3.9.3",
|
||||
"version": "v3.10.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/twigphp/Twig.git",
|
||||
"reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58"
|
||||
"reference": "3af5ab2e52279e5e23dc192b1a26db3b8cffa4e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58",
|
||||
"reference": "a842d75fed59cdbcbd3a3ad7fb9eb768fc350d58",
|
||||
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3af5ab2e52279e5e23dc192b1a26db3b8cffa4e7",
|
||||
"reference": "3af5ab2e52279e5e23dc192b1a26db3b8cffa4e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10163,7 +10167,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/twigphp/Twig/issues",
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.9.3"
|
||||
"source": "https://github.com/twigphp/Twig/tree/v3.10.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10175,7 +10179,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-18T11:59:33+00:00"
|
||||
"time": "2024-05-12T06:16:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
@@ -10336,16 +10340,16 @@
|
||||
},
|
||||
{
|
||||
"name": "zircote/swagger-php",
|
||||
"version": "4.9.0",
|
||||
"version": "4.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zircote/swagger-php.git",
|
||||
"reference": "b46a36d006f4db4d761995a5add1e7ab0386ed1d"
|
||||
"reference": "256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/b46a36d006f4db4d761995a5add1e7ab0386ed1d",
|
||||
"reference": "b46a36d006f4db4d761995a5add1e7ab0386ed1d",
|
||||
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2",
|
||||
"reference": "256d42cb07ba1c2206d66bc7516ee3d3e3e9f0b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10411,9 +10415,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/zircote/swagger-php/issues",
|
||||
"source": "https://github.com/zircote/swagger-php/tree/4.9.0"
|
||||
"source": "https://github.com/zircote/swagger-php/tree/4.9.2"
|
||||
},
|
||||
"time": "2024-04-18T22:32:11+00:00"
|
||||
"time": "2024-05-02T21:36:00+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
@@ -10490,16 +10494,16 @@
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/xdebug-handler.git",
|
||||
"reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255"
|
||||
"reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/4f988f8fdf580d53bdb2d1278fe93d1ed5462255",
|
||||
"reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255",
|
||||
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
|
||||
"reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10536,7 +10540,7 @@
|
||||
"support": {
|
||||
"irc": "ircs://irc.libera.chat:6697/composer",
|
||||
"issues": "https://github.com/composer/xdebug-handler/issues",
|
||||
"source": "https://github.com/composer/xdebug-handler/tree/3.0.4"
|
||||
"source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10552,7 +10556,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-26T18:29:49+00:00"
|
||||
"time": "2024-05-06T16:37:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dama/doctrine-test-bundle",
|
||||
@@ -10708,16 +10712,16 @@
|
||||
},
|
||||
{
|
||||
"name": "doctrine/doctrine-fixtures-bundle",
|
||||
"version": "3.5.1",
|
||||
"version": "3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/DoctrineFixturesBundle.git",
|
||||
"reference": "c808a0c85c38c8ee265cc8405b456c1d2b38567d"
|
||||
"reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/c808a0c85c38c8ee265cc8405b456c1d2b38567d",
|
||||
"reference": "c808a0c85c38c8ee265cc8405b456c1d2b38567d",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/87f5d53708a3855aa018bf0a00d0d4b0ef58a956",
|
||||
"reference": "87f5d53708a3855aa018bf0a00d0d4b0ef58a956",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10746,7 +10750,7 @@
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Bundle\\FixturesBundle\\": ""
|
||||
"Doctrine\\Bundle\\FixturesBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
@@ -10775,7 +10779,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues",
|
||||
"source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.5.1"
|
||||
"source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10791,7 +10795,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-19T12:48:54+00:00"
|
||||
"time": "2024-05-02T18:06:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fakerphp/faker",
|
||||
@@ -10858,16 +10862,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.54.0",
|
||||
"version": "v3.56.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08"
|
||||
"reference": "69c6168ae8bc96dc656c7f6c7271120a68ae5903"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2aecbc8640d7906c38777b3dcab6f4ca79004d08",
|
||||
"reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/69c6168ae8bc96dc656c7f6c7271120a68ae5903",
|
||||
"reference": "69c6168ae8bc96dc656c7f6c7271120a68ae5903",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -10939,7 +10943,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.54.0"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.56.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -10947,7 +10951,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-04-17T08:12:13+00:00"
|
||||
"time": "2024-05-10T11:31:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
|
||||
@@ -118,9 +118,9 @@ kimai:
|
||||
# mapping a "role name" to an array of "permission names"
|
||||
roles:
|
||||
ROLE_USER: ['view_team_member','time_team_project','create_tag','view_reporting']
|
||||
ROLE_TEAMLEAD: ['view_rate_own_timesheet','view_rate_other_timesheet','hourly-rate_own_profile','view_team_member']
|
||||
ROLE_ADMIN: ['hourly-rate_own_profile','edit_exported_timesheet','teams_own_profile','view_team_member','view_all_data','contract_other_profile']
|
||||
ROLE_SUPER_ADMIN: ['hourly-rate_own_profile','hourly-rate_other_profile','roles_own_profile','supervisor_own_profile','system_information','system_configuration','plugins','edit_exported_timesheet','teams_own_profile','view_team_member','upload_invoice_template','view_all_data','contract_other_profile']
|
||||
ROLE_TEAMLEAD: ['view_rate_own_timesheet','view_rate_other_timesheet','hourly-rate_own_profile','view_team_member','hours_other_profile']
|
||||
ROLE_ADMIN: ['hourly-rate_own_profile','edit_exported_timesheet','teams_own_profile','view_team_member','view_all_data','contract_other_profile','hours_other_profile']
|
||||
ROLE_SUPER_ADMIN: ['hourly-rate_own_profile','hourly-rate_other_profile','roles_own_profile','supervisor_own_profile','system_information','system_configuration','plugins','edit_exported_timesheet','teams_own_profile','view_team_member','upload_invoice_template','view_all_data','contract_other_profile','hours_other_profile']
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ when@prod:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!deprecation"]
|
||||
# deactivated, because currently there are too many deprecations cause by gedmo and doctrine
|
||||
# TODO reactivate once the many Doctrine deprecations are fixed
|
||||
# deprecation:
|
||||
# type: stream
|
||||
# channels: ["deprecation"]
|
||||
|
||||
@@ -72,8 +72,8 @@ security:
|
||||
login_link:
|
||||
check_route: link_login_check
|
||||
signature_properties: ['id']
|
||||
lifetime: 300
|
||||
max_uses: 1
|
||||
lifetime: 900
|
||||
max_uses: 3
|
||||
|
||||
access_decision_manager:
|
||||
# only grants access if there is no voter denying access
|
||||
@@ -108,7 +108,3 @@ when@test:
|
||||
cost: 4 # Lowest possible value for bcrypt
|
||||
time_cost: 3 # Lowest possible value for argon
|
||||
memory_cost: 10 # Lowest possible value for argon
|
||||
|
||||
firewalls:
|
||||
secured_area:
|
||||
http_basic: ~
|
||||
|
||||
@@ -1158,11 +1158,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/TimesheetTeamController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$plainPassword of method Symfony\\\\Component\\\\PasswordHasher\\\\Hasher\\\\UserPasswordHasherInterface\\:\\:hashPassword\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/UserController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$replace of method App\\\\User\\\\UserService\\:\\:deleteUser\\(\\) expects App\\\\Entity\\\\User\\|null, mixed given\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -16,30 +16,19 @@ final class ApiRequestMatcher implements RequestMatcherInterface
|
||||
{
|
||||
public function matches(Request $request): bool
|
||||
{
|
||||
// we do not want to handle URLs that
|
||||
// we do not want to handle URLs that are not in the API scope
|
||||
if (!str_starts_with($request->getRequestUri(), '/api/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// API documentation is only available to registered users
|
||||
// API documentation is only available to registered and logged-in users
|
||||
if (str_starts_with($request->getRequestUri(), '/api/doc')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// let's use this firewall if a Bearer token is set in the header
|
||||
// other cases like "bearer" are rejected earlier
|
||||
if (($auth = $request->headers->get('Authorization')) !== null && str_starts_with($auth, 'Bearer ')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// let's use this firewall if the deprecated username & token combination is available
|
||||
if ($request->headers->has(TokenAuthenticator::HEADER_USERNAME) &&
|
||||
$request->headers->has(TokenAuthenticator::HEADER_TOKEN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// checking for a previous session allows us to skip the API firewall and token access handler
|
||||
// we simply re-use the existing session when doing API calls from the frontend
|
||||
// we simply re-use the existing session when doing API calls from the frontend.
|
||||
// it is not necessary to check headers. if there is no valid session, we should always use this firewall
|
||||
return !$request->hasPreviousSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,5 +56,5 @@ abstract class AbstractRoleCommand extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
abstract protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void;
|
||||
abstract protected function executeRoleCommand(UserService $userService, SymfonyStyle $output, User $user, bool $super, $role): void;
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ final class DemoteUserCommand extends AbstractRoleCommand
|
||||
);
|
||||
}
|
||||
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
protected function executeRoleCommand(UserService $userService, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
{
|
||||
$username = $user->getUserIdentifier();
|
||||
if ($super) {
|
||||
if ($user->isSuperAdmin()) {
|
||||
$user->setSuperAdmin(false);
|
||||
$manipulator->saveUser($user);
|
||||
$userService->saveUser($user);
|
||||
$output->success(sprintf('Super administrator role has been removed from the user "%s".', $username));
|
||||
} else {
|
||||
$output->warning(sprintf('User "%s" doesn\'t have the super administrator role.', $username));
|
||||
@@ -47,7 +47,7 @@ final class DemoteUserCommand extends AbstractRoleCommand
|
||||
} else {
|
||||
if ($user->hasRole($role)) {
|
||||
$user->removeRole($role);
|
||||
$manipulator->saveUser($user);
|
||||
$userService->saveUser($user);
|
||||
$output->success(sprintf('Role "%s" has been removed from user "%s".', $role, $username));
|
||||
} else {
|
||||
$output->warning(sprintf('User "%s" didn\'t have "%s" role.', $username, $role));
|
||||
|
||||
@@ -33,13 +33,13 @@ final class PromoteUserCommand extends AbstractRoleCommand
|
||||
);
|
||||
}
|
||||
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
protected function executeRoleCommand(UserService $userService, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
{
|
||||
$username = $user->getUserIdentifier();
|
||||
if ($super) {
|
||||
if (!$user->isSuperAdmin()) {
|
||||
$user->setSuperAdmin(true);
|
||||
$manipulator->saveUser($user);
|
||||
$userService->saveUser($user);
|
||||
$output->success(sprintf('User "%s" has been promoted as a super administrator.', $username));
|
||||
} else {
|
||||
$output->warning(sprintf('User "%s" does already have the super administrator role.', $username));
|
||||
@@ -47,7 +47,7 @@ final class PromoteUserCommand extends AbstractRoleCommand
|
||||
} else {
|
||||
if (!$user->hasRole($role)) {
|
||||
$user->addRole($role);
|
||||
$manipulator->saveUser($user);
|
||||
$userService->saveUser($user);
|
||||
$output->success(sprintf('Role "%s" has been added to user "%s".', $role, $username));
|
||||
} else {
|
||||
$output->warning(sprintf('User "%s" did already have "%s" role.', $username, $role));
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.16.1';
|
||||
public const VERSION = '2.17.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 21601;
|
||||
public const VERSION_ID = 21700;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ final class ContractController extends AbstractController
|
||||
{
|
||||
$currentUser = $this->getUser();
|
||||
$dateTimeFactory = $this->getDateTimeFactory($currentUser);
|
||||
$canChangeUser = $this->isGranted('contract_other_profile');
|
||||
$canChangeUser = $this->isGranted('hours_other_profile');
|
||||
$defaultDate = $dateTimeFactory->createStartOfYear();
|
||||
$now = $dateTimeFactory->createDateTime();
|
||||
|
||||
|
||||
@@ -58,7 +58,12 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
#[Route(path: '/admin/project')]
|
||||
final class ProjectController extends AbstractController
|
||||
{
|
||||
public function __construct(private ProjectRepository $repository, private SystemConfiguration $configuration, private EventDispatcherInterface $dispatcher, private ProjectService $projectService)
|
||||
public function __construct(
|
||||
private readonly ProjectRepository $repository,
|
||||
private readonly SystemConfiguration $configuration,
|
||||
private readonly EventDispatcherInterface $dispatcher,
|
||||
private readonly ProjectService $projectService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -480,11 +485,17 @@ final class ProjectController extends AbstractController
|
||||
|
||||
$csrfTokenManager->refreshToken('project.duplicate');
|
||||
|
||||
$newProject = $projectDuplicationService->duplicate($project, $project->getName() . ' [COPY]');
|
||||
try {
|
||||
$newProject = $projectDuplicationService->duplicate($project, $project->getName() . ' [COPY]');
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
$this->flashSuccess('action.update.success');
|
||||
return $this->redirectToRoute('project_details', ['id' => $newProject->getId()]);
|
||||
} catch (\Exception $ex) {
|
||||
$this->logException($ex);
|
||||
$this->flashError('action.update.error', 'Failed to copy project: ' . $ex->getMessage());
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('project_details', ['id' => $newProject->getId()]);
|
||||
return $this->redirectToRoute('admin_project');
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}/delete', name: 'admin_project_delete', methods: ['GET', 'POST'])]
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Entity\User;
|
||||
use App\Event\PrepareUserEvent;
|
||||
use App\Event\UserPreferenceDisplayEvent;
|
||||
@@ -29,7 +28,6 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -41,7 +39,10 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
#[IsGranted('view_user')]
|
||||
final class UserController extends AbstractController
|
||||
{
|
||||
public function __construct(private UserPasswordHasherInterface $passwordHasher, private UserRepository $repository, private EventDispatcherInterface $dispatcher)
|
||||
public function __construct(
|
||||
private readonly UserRepository $repository,
|
||||
private readonly EventDispatcherInterface $dispatcher
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -100,37 +101,23 @@ final class UserController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
private function createNewDefaultUser(SystemConfiguration $config): User
|
||||
{
|
||||
$user = new User();
|
||||
$user->setEnabled(true);
|
||||
$user->setRoles([User::DEFAULT_ROLE]);
|
||||
$user->setTimezone($config->getUserDefaultTimezone());
|
||||
$user->setLanguage($config->getUserDefaultLanguage());
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
#[Route(path: '/create', name: 'admin_user_create', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('create_user')]
|
||||
public function createAction(Request $request, SystemConfiguration $config, UserRepository $userRepository, EventDispatcherInterface $dispatcher): Response
|
||||
public function createAction(Request $request, UserService $userService, EventDispatcherInterface $dispatcher): Response
|
||||
{
|
||||
$user = $this->createNewDefaultUser($config);
|
||||
$user = $userService->createNewUser();
|
||||
$editForm = $this->getCreateUserForm($user);
|
||||
|
||||
$editForm->handleRequest($request);
|
||||
|
||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||
$password = $this->passwordHasher->hashPassword($user, $user->getPlainPassword());
|
||||
$user->setPassword($password);
|
||||
|
||||
$userRepository->saveUser($user);
|
||||
$userService->saveUser($user);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
try {
|
||||
$event = new PrepareUserEvent($user, false);
|
||||
$dispatcher->dispatch($event);
|
||||
$userRepository->saveUser($user);
|
||||
$this->repository->saveUser($user);
|
||||
} catch (\Exception $ex) {
|
||||
// it should be no problem, if creating default user preferences fails
|
||||
}
|
||||
|
||||
@@ -481,6 +481,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
|
||||
$this->addTeam($team);
|
||||
}
|
||||
|
||||
$this->number = null;
|
||||
$currentMeta = $this->meta;
|
||||
$this->meta = new ArrayCollection();
|
||||
/** @var ProjectMeta $meta */
|
||||
|
||||
@@ -71,7 +71,7 @@ class Tag
|
||||
|
||||
public function setName(?string $tagName): Tag
|
||||
{
|
||||
$this->name = $tagName;
|
||||
$this->name = $tagName !== null ? trim($tagName) : $tagName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
private ?string $description = null;
|
||||
#[ORM\Column(name: 'rate', type: 'float', nullable: false)]
|
||||
#[Assert\GreaterThanOrEqual(0)]
|
||||
#[Assert\NotNull]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
private float $rate = 0.00;
|
||||
@@ -224,8 +225,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
|
||||
/**
|
||||
* Get entry id, returns null for new entities which were not persisted.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getId(): ?int
|
||||
{
|
||||
@@ -282,10 +281,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
return $this->end === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime $end
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setEnd(?DateTime $end): Timesheet
|
||||
{
|
||||
$this->end = $end;
|
||||
@@ -300,10 +295,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $duration
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setDuration(?int $duration): Timesheet
|
||||
{
|
||||
$this->duration = $duration;
|
||||
@@ -313,9 +304,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
|
||||
/**
|
||||
* Do not rely on the results of this method for running records.
|
||||
*
|
||||
* @param bool $calculate
|
||||
* @return int|null
|
||||
*/
|
||||
public function getDuration(bool $calculate = true): ?int
|
||||
{
|
||||
@@ -384,11 +372,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $rate
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setRate($rate): Timesheet
|
||||
public function setRate(float $rate): Timesheet
|
||||
{
|
||||
$this->rate = $rate;
|
||||
|
||||
@@ -454,18 +438,11 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isExported(): bool
|
||||
{
|
||||
return $this->exported;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $exported
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setExported(bool $exported): Timesheet
|
||||
{
|
||||
$this->exported = $exported;
|
||||
@@ -473,9 +450,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTimezone(): ?string
|
||||
{
|
||||
return $this->timezone;
|
||||
@@ -486,8 +460,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
* It is reserved for some very rare use-cases.
|
||||
*
|
||||
* @internal
|
||||
* @param string $timezone
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setTimezone(string $timezone): Timesheet
|
||||
{
|
||||
@@ -498,8 +470,6 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
|
||||
/**
|
||||
* This method returns ALWAYS: "timesheet"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
@@ -635,6 +605,10 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
|
||||
|
||||
public function setMetaField(MetaTableTypeInterface $meta): EntityWithMetaFields
|
||||
{
|
||||
// this needs to be done, otherwise doctrine will not see the item as changed
|
||||
// and the calculators will not run
|
||||
$this->modifiedAt = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
|
||||
|
||||
if (null === ($current = $this->getMetaField($meta->getName()))) {
|
||||
$meta->setEntity($this);
|
||||
$this->meta->add($meta);
|
||||
|
||||
@@ -141,6 +141,11 @@ class PageActionsEvent extends ThemeEvent
|
||||
$this->payload['actions'][$key] = null;
|
||||
}
|
||||
|
||||
public function addQuickImport(string $url): void
|
||||
{
|
||||
$this->addAction('import', ['url' => $url, 'class' => 'toolbar-action', 'title' => 'import', 'icon' => 'upload', 'translation_domain' => 'actions']);
|
||||
}
|
||||
|
||||
public function addQuickExport(string $url): void
|
||||
{
|
||||
$this->addAction('download', ['url' => $url, 'class' => 'toolbar-action', 'title' => 'export']);
|
||||
|
||||
@@ -94,7 +94,7 @@ final class MenuSubscriber implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
$contract = new MenuItemModel('contract', 'work_contract', null, [], 'contract');
|
||||
if ($user->hasContractSettings() || $auth->isGranted('contract_other_profile')) {
|
||||
if ($user->hasContractSettings() || $auth->isGranted('hours_other_profile')) {
|
||||
$contract->addChild(new MenuItemModel('contract_status', 'work_times', 'user_contract', [], 'work_times'));
|
||||
}
|
||||
|
||||
|
||||
@@ -45,29 +45,47 @@ final class TagArrayToStringTransformer implements DataTransformerInterface
|
||||
*
|
||||
* @see \Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer::reverseTransform()
|
||||
*
|
||||
* @param string|null $value
|
||||
* @param array<string>|string|null $value
|
||||
* @return Tag[]
|
||||
* @throws TransformationFailedException
|
||||
*/
|
||||
public function reverseTransform(mixed $value): mixed
|
||||
public function reverseTransform(mixed $value): array
|
||||
{
|
||||
// check for empty tag list
|
||||
if ('' === $value || null === $value) {
|
||||
return [];
|
||||
}
|
||||
$names = array_filter(array_unique(array_map('trim', explode(',', $value))));
|
||||
if (!\is_array($value)) {
|
||||
$names = array_filter(array_unique(array_map('trim', explode(',', $value))));
|
||||
} else {
|
||||
$names = $value;
|
||||
}
|
||||
|
||||
// get the current tags and find the new ones that should be created
|
||||
$tags = $this->tagRepository->findBy(['name' => $names]);
|
||||
if ($this->create) {
|
||||
// works, because of the implicit case: (string) $tag
|
||||
$newNames = array_diff($names, $tags);
|
||||
$tags = [];
|
||||
foreach ($names as $tagName) {
|
||||
if ($tagName === null || $tagName === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($newNames as $name) {
|
||||
$tagName = trim($tagName);
|
||||
$tag = null;
|
||||
|
||||
if (is_numeric($tagName)) {
|
||||
$tag = $this->tagRepository->find($tagName);
|
||||
}
|
||||
|
||||
if ($tag === null) {
|
||||
$tag = $this->tagRepository->findTagByName($tagName);
|
||||
}
|
||||
|
||||
// get the current tags and find the new ones that should be created
|
||||
if ($this->create && $tag === null) {
|
||||
$tag = new Tag();
|
||||
$tag->setName(mb_substr($name, 0, 100));
|
||||
$tag->setName(mb_substr($tagName, 0, 100));
|
||||
$this->tagRepository->saveTag($tag);
|
||||
}
|
||||
|
||||
if ($tag !== null) {
|
||||
$tags[] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ trait FormTrait
|
||||
return;
|
||||
}
|
||||
|
||||
$options['projects'] = $data['project'];
|
||||
$options['projects'] = \is_string($data['project']) ? (int) $data['project'] : $data['project'];
|
||||
|
||||
$event->getForm()->add('activity', ActivityType::class, $options);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ trait ToolbarFormTrait
|
||||
|
||||
protected function addPageSizeChoice(FormBuilderInterface $builder): void
|
||||
{
|
||||
$builder->add('pageSize', PageSizeType::class);
|
||||
$builder->add('size', PageSizeType::class);
|
||||
}
|
||||
|
||||
protected function addUserRoleChoice(FormBuilderInterface $builder): void
|
||||
|
||||
@@ -36,13 +36,15 @@ final class TagsSelectType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
if (!$options['allow_create']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
|
||||
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($options) {
|
||||
/** @var array<string> $tagIds */
|
||||
$tagIds = $event->getData();
|
||||
|
||||
// this is mainly here, because the link from tags index page uses the non-array syntax
|
||||
if (\is_string($tagIds) || \is_int($tagIds)) {
|
||||
$tagIds = array_filter(array_unique(array_map('trim', explode(',', $tagIds))));
|
||||
}
|
||||
|
||||
if (!\is_array($tagIds)) {
|
||||
return;
|
||||
}
|
||||
@@ -59,13 +61,15 @@ final class TagsSelectType extends AbstractType
|
||||
$tag = $this->tagRepository->findTagByName($tagId);
|
||||
}
|
||||
|
||||
if ($tag === null) {
|
||||
if ($options['allow_create'] && $tag === null) {
|
||||
$tag = new Tag();
|
||||
$tag->setName(mb_substr($tagId, 0, 100));
|
||||
$tag->setName($tagId);
|
||||
$this->tagRepository->saveTag($tag);
|
||||
}
|
||||
|
||||
$tags[] = $tag->getId();
|
||||
if ($tag !== null) {
|
||||
$tags[] = $tag->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$event->setData($tags);
|
||||
@@ -79,6 +83,9 @@ final class TagsSelectType extends AbstractType
|
||||
'class' => Tag::class,
|
||||
'label' => 'tag',
|
||||
'allow_create' => false,
|
||||
'choice_value' => function (Tag $tag) {
|
||||
return $tag->getId();
|
||||
},
|
||||
'choice_attr' => function (Tag $tag) {
|
||||
$color = $tag->getColor();
|
||||
if ($color === null) {
|
||||
|
||||
@@ -60,7 +60,7 @@ class Kernel extends BaseKernel
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->environment === 'test' && getenv('TEST_WITH_BUNDLES') === false) {
|
||||
if ($this->environment === 'test') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ class Kernel extends BaseKernel
|
||||
$loader->load($file->getPathname());
|
||||
}
|
||||
|
||||
if (is_file($confDir . '/packages/local.yaml')) {
|
||||
if ($this->environment !== 'test' && is_file($confDir . '/packages/local.yaml')) {
|
||||
$loader->load($confDir . '/packages/local.yaml');
|
||||
}
|
||||
$loader->load($confDir . '/services' . self::CONFIG_EXTS, 'glob');
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
namespace App\Project;
|
||||
|
||||
use App\Entity\ActivityRate;
|
||||
use App\Entity\Project;
|
||||
use App\Entity\ProjectRate;
|
||||
use App\Repository\ActivityRateRepository;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Repository\ProjectRateRepository;
|
||||
@@ -19,10 +17,10 @@ use App\Repository\ProjectRateRepository;
|
||||
final class ProjectDuplicationService
|
||||
{
|
||||
public function __construct(
|
||||
private ProjectService $projectService,
|
||||
private ActivityRepository $activityRepository,
|
||||
private ProjectRateRepository $projectRateRepository,
|
||||
private ActivityRateRepository $activityRateRepository
|
||||
private readonly ProjectService $projectService,
|
||||
private readonly ActivityRepository $activityRepository,
|
||||
private readonly ProjectRateRepository $projectRateRepository,
|
||||
private readonly ActivityRateRepository $activityRateRepository
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -30,6 +28,7 @@ final class ProjectDuplicationService
|
||||
{
|
||||
$newProject = clone $project;
|
||||
$newProject->setName($newName);
|
||||
$newProject->setNumber($this->projectService->calculateNextProjectNumber());
|
||||
|
||||
foreach ($project->getTeams() as $team) {
|
||||
$newProject->addTeam($team);
|
||||
@@ -49,7 +48,6 @@ final class ProjectDuplicationService
|
||||
$this->projectService->saveNewProject($newProject);
|
||||
|
||||
foreach ($this->projectRateRepository->getRatesForProject($project) as $rate) {
|
||||
/** @var ProjectRate $newRate */
|
||||
$newRate = clone $rate;
|
||||
$newRate->setProject($newProject);
|
||||
$this->projectRateRepository->saveRate($newRate);
|
||||
@@ -68,7 +66,6 @@ final class ProjectDuplicationService
|
||||
$this->activityRepository->saveActivity($newActivity);
|
||||
|
||||
foreach ($this->activityRateRepository->getRatesForActivity($activity) as $rate) {
|
||||
/** @var ActivityRate $newRate */
|
||||
$newRate = clone $rate;
|
||||
$newRate->setActivity($newActivity);
|
||||
$this->activityRateRepository->saveRate($newRate);
|
||||
|
||||
@@ -112,7 +112,7 @@ final class ProjectService
|
||||
return $this->repository->findOneBy(['number' => $number]);
|
||||
}
|
||||
|
||||
private function calculateNextProjectNumber(): ?string
|
||||
public function calculateNextProjectNumber(): ?string
|
||||
{
|
||||
$format = $this->configuration->find('project.number_format');
|
||||
if (empty($format) || !\is_string($format)) {
|
||||
|
||||
@@ -30,7 +30,7 @@ class BaseQuery
|
||||
/** @var array<string, string|int|null|bool|array<mixed>|DateRange> */
|
||||
private array $defaults = [
|
||||
'page' => 1,
|
||||
'pageSize' => self::DEFAULT_PAGESIZE,
|
||||
'size' => self::DEFAULT_PAGESIZE,
|
||||
'orderBy' => 'id',
|
||||
'order' => self::ORDER_ASC,
|
||||
'searchTerm' => null,
|
||||
@@ -137,6 +137,16 @@ class BaseQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSize(): int
|
||||
{
|
||||
return $this->getPageSize();
|
||||
}
|
||||
|
||||
public function setSize(?int $size): void
|
||||
{
|
||||
$this->setPageSize($size);
|
||||
}
|
||||
|
||||
public function getOrderBy(): string
|
||||
{
|
||||
return $this->orderBy;
|
||||
|
||||
@@ -53,6 +53,8 @@ final class SessionHandler extends PdoSessionHandler
|
||||
if (false === $limit->isAccepted()) {
|
||||
throw new BadRequestHttpException('Too many requests with invalid Session ID. Prediction attack?');
|
||||
}
|
||||
|
||||
usleep(250000); // slow down potential attacks
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
@@ -60,6 +60,7 @@ class UserService
|
||||
{
|
||||
$user = new User();
|
||||
$user->setEnabled(true);
|
||||
$user->setRoles([User::DEFAULT_ROLE]);
|
||||
$user->setTimezone($this->configuration->getUserDefaultTimezone());
|
||||
$user->setLanguage($this->configuration->getUserDefaultLanguage());
|
||||
$user->setPreferenceValue(UserPreference::SKIN, $this->configuration->getUserDefaultTheme());
|
||||
@@ -92,6 +93,7 @@ class UserService
|
||||
|
||||
$this->hashPassword($user);
|
||||
$this->hashApiToken($user);
|
||||
$user->eraseCredentials();
|
||||
|
||||
$this->dispatcher->dispatch(new UserCreatePreEvent($user)); // @CloudRequired
|
||||
$this->repository->saveUser($user);
|
||||
@@ -120,6 +122,7 @@ class UserService
|
||||
|
||||
$this->hashPassword($user);
|
||||
$this->hashApiToken($user);
|
||||
$user->eraseCredentials();
|
||||
|
||||
$this->dispatcher->dispatch(new UserUpdatePreEvent($user));
|
||||
$this->repository->saveUser($user);
|
||||
@@ -179,7 +182,6 @@ class UserService
|
||||
|
||||
$password = $this->passwordHasher->hashPassword($user, $plain);
|
||||
$user->setPassword($password);
|
||||
$user->eraseCredentials();
|
||||
}
|
||||
|
||||
private function hashApiToken(User $user): void
|
||||
@@ -192,7 +194,6 @@ class UserService
|
||||
|
||||
$password = $this->passwordHasher->hashPassword($user, $plain);
|
||||
$user->setApiToken($password);
|
||||
$user->eraseCredentials();
|
||||
}
|
||||
|
||||
public function deleteUser(User $delete, ?User $replace = null): void
|
||||
|
||||
@@ -35,6 +35,7 @@ final class UserVoter extends Voter
|
||||
'hourly-rate',
|
||||
'view_team_member',
|
||||
'contract',
|
||||
'hours',
|
||||
'supervisor',
|
||||
];
|
||||
|
||||
@@ -73,6 +74,10 @@ final class UserVoter extends Voter
|
||||
return $this->permissionManager->hasRolePermission($user, 'contract_other_profile');
|
||||
}
|
||||
|
||||
if ($attribute === 'hours') {
|
||||
return $this->permissionManager->hasRolePermission($user, 'hours_other_profile');
|
||||
}
|
||||
|
||||
if ($attribute === 'access_user') {
|
||||
return $user->canSeeUser($subject);
|
||||
}
|
||||
|
||||
@@ -45,28 +45,24 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block report_form_layout %}
|
||||
{{ form_start(form, {'attr': {'class': 'form-reporting', 'id': 'report-form'}}) }}
|
||||
<div class="btn-list w-100">
|
||||
{{ form_widget(form.month, {'label': false}) }}
|
||||
{{ form_widget(form.customer, {'label': false, 'placeholder': 'please_choose'}) }}
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ icon('filter', true) }}
|
||||
</button>
|
||||
<ul class="dropdown-menu checkbox-menu">
|
||||
{% for option in form.budgetType.children %}
|
||||
<li class="dropdown-item">
|
||||
{{ form_widget(option) }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li class="dropdown-divider"></li>
|
||||
{{ form_widget(form.month, {'label': false}) }}
|
||||
{{ form_widget(form.customer, {'label': false, 'placeholder': 'please_choose'}) }}
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{{ icon('filter', true) }}
|
||||
</button>
|
||||
<ul class="dropdown-menu checkbox-menu">
|
||||
{% for option in form.budgetType.children %}
|
||||
<li class="dropdown-item">
|
||||
{{ form_widget(form.includeNoWork) }}
|
||||
{{ form_widget(option) }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<li class="dropdown-divider"></li>
|
||||
<li class="dropdown-item">
|
||||
{{ form_widget(form.includeNoWork) }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block report %}
|
||||
|
||||
@@ -81,7 +81,7 @@ class ActivityControllerTest extends ControllerBaseTest
|
||||
$client->submit($form, [
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'customers' => [1],
|
||||
'projects' => [1],
|
||||
'page' => 1,
|
||||
@@ -125,7 +125,7 @@ class ActivityControllerTest extends ControllerBaseTest
|
||||
$client->submit($form, [
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'customers' => [1],
|
||||
'projects' => [1],
|
||||
'page' => 1,
|
||||
|
||||
@@ -32,7 +32,20 @@ class ContractControllerTest extends ControllerBaseTest
|
||||
self::assertEquals(0, $node->count());
|
||||
}
|
||||
|
||||
public function testAdminCanChangeUser(): void
|
||||
public function testTeamleadCanChangeUser(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
|
||||
$this->assertAccessIsGranted($client, '/contract');
|
||||
$content = $client->getResponse()->getContent();
|
||||
self::assertNotFalse($content);
|
||||
self::assertStringContainsString('No target hours have been configured', $content);
|
||||
$node = $client->getCrawler()->filter('select#user');
|
||||
self::assertEquals(1, $node->count());
|
||||
$node = $client->getCrawler()->filter('a.alert-link');
|
||||
self::assertEquals(0, $node->count());
|
||||
}
|
||||
|
||||
public function testAdminCanConfigureUser(): void
|
||||
{
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/contract');
|
||||
@@ -41,5 +54,7 @@ class ContractControllerTest extends ControllerBaseTest
|
||||
self::assertStringContainsString('No target hours have been configured', $content);
|
||||
$node = $client->getCrawler()->filter('select#user');
|
||||
self::assertEquals(1, $node->count());
|
||||
$node = $client->getCrawler()->filter('a.alert-link');
|
||||
self::assertEquals(1, $node->count());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class CustomerControllerTest extends ControllerBaseTest
|
||||
$client->submit($form, [
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
@@ -119,7 +119,7 @@ class CustomerControllerTest extends ControllerBaseTest
|
||||
$client->submit($form, [
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class PermissionControllerTest extends ControllerBaseTest
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/permissions');
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 133);
|
||||
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 134);
|
||||
$this->assertPageActions($client, [
|
||||
'create modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'),
|
||||
]);
|
||||
|
||||
@@ -91,7 +91,7 @@ class ProjectControllerTest extends ControllerBaseTest
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'customers' => [1],
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
@@ -134,7 +134,7 @@ class ProjectControllerTest extends ControllerBaseTest
|
||||
'searchTerm' => 'feature:timetracking foo',
|
||||
'visibility' => 1,
|
||||
'customers' => [1],
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ class TimesheetControllerTest extends ControllerBaseTest
|
||||
$form = $client->getCrawler()->filter('form.searchform')->form();
|
||||
$client->submit($form, [
|
||||
'state' => 1,
|
||||
'pageSize' => 25,
|
||||
'size' => 25,
|
||||
'daterange' => $dateRange,
|
||||
'customers' => [1],
|
||||
'projects' => [1],
|
||||
|
||||
@@ -72,7 +72,7 @@ class TimesheetTeamControllerTest extends ControllerBaseTest
|
||||
$client->submit($form, [
|
||||
'state' => 1,
|
||||
'users' => [$user->getId()],
|
||||
'pageSize' => 25,
|
||||
'size' => 25,
|
||||
'daterange' => $dateRange,
|
||||
'customers' => [],
|
||||
]);
|
||||
|
||||
@@ -55,7 +55,7 @@ class UserControllerTest extends ControllerBaseTest
|
||||
'searchTerm' => 'hourly_rate:35 tony',
|
||||
'role' => 'ROLE_TEAMLEAD',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
@@ -89,7 +89,7 @@ class UserControllerTest extends ControllerBaseTest
|
||||
'searchTerm' => 'hourly_rate:35 tony',
|
||||
'role' => 'ROLE_TEAMLEAD',
|
||||
'visibility' => 1,
|
||||
'pageSize' => 50,
|
||||
'size' => 50,
|
||||
'page' => 1,
|
||||
]);
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ class TagArrayToStringTransformerTest extends TestCase
|
||||
];
|
||||
|
||||
$repository = $this->getMockBuilder(TagRepository::class)
|
||||
->onlyMethods(['findBy', 'saveTag'])
|
||||
->onlyMethods(['findTagByName', 'saveTag'])
|
||||
->disableOriginalConstructor()->getMock();
|
||||
$repository->expects($this->once())->method('findBy')->willReturn($results);
|
||||
$repository->expects($this->exactly(3))->method('findTagByName')->willReturnOnConsecutiveCalls($results[0], $results[1]);
|
||||
|
||||
$sut = new TagArrayToStringTransformer($repository, true);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class BaseQueryTest extends TestCase
|
||||
$sut->setPageSize(99);
|
||||
$sut->setSearchTerm(new SearchTerm('sdf'));
|
||||
|
||||
$this->resetByFormError($sut, ['order', 'orderBy', 'page', 'pageSize', 'searchTerm']);
|
||||
$this->resetByFormError($sut, ['order', 'orderBy', 'page', 'size', 'searchTerm']);
|
||||
|
||||
self::assertEquals(1, $sut->getPage());
|
||||
self::assertEquals(50, $sut->getPageSize());
|
||||
|
||||
Reference in New Issue
Block a user