diff --git a/README.md b/README.md index 4c0ed1c3..6a493655 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ ![Docker Build Status](https://github.com/Part-DB/Part-DB-symfony/workflows/Docker%20Image%20Build/badge.svg) [![Crowdin](https://badges.crowdin.net/e/8325196085d4bee8c04b75f7c915452a/localized.svg)](https://part-db.crowdin.com/part-db) +*When updgrading from a version from before 2022-11-27, please read [this](https://github.com/Part-DB/Part-DB-symfony/discussions/193) before upgrading!* + # Part-DB Part-DB is an Open-Source inventory managment system for your electronic components. It is installed on a web server and so can be accessed with any browser without the need to install additional software. diff --git a/assets/css/app.css b/assets/css/app.css index 61b01f81..37c57b8a 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -871,3 +871,10 @@ table.dataTable tr.selected td.select-checkbox:after, table.dataTable tr.selecte width: 100%; } +/*********************************************** + * Permission checkboxes + ***********************************************/ +.permission-checkbox:checked { + background-color: var(--bs-success); + border-color: var(--bs-success); +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index d7d01eed..281ed4d4 100644 --- a/composer.lock +++ b/composer.lock @@ -1455,16 +1455,16 @@ }, { "name": "doctrine/orm", - "version": "2.13.3", + "version": "2.13.4", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "e750360bd52b080c4cbaaee1b48b80f7dc873b36" + "reference": "a5a6cc6630ce497290396d5f206887227820a634" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/e750360bd52b080c4cbaaee1b48b80f7dc873b36", - "reference": "e750360bd52b080c4cbaaee1b48b80f7dc873b36", + "url": "https://api.github.com/repos/doctrine/orm/zipball/a5a6cc6630ce497290396d5f206887227820a634", + "reference": "a5a6cc6630ce497290396d5f206887227820a634", "shasum": "" }, "require": { @@ -1493,13 +1493,13 @@ "doctrine/annotations": "^1.13", "doctrine/coding-standard": "^9.0.2 || ^10.0", "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/phpstan": "~1.4.10 || 1.8.5", + "phpstan/phpstan": "~1.4.10 || 1.9.2", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.1", "symfony/cache": "^4.4 || ^5.4 || ^6.0", "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0", - "vimeo/psalm": "4.27.0" + "vimeo/psalm": "4.30.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", @@ -1549,22 +1549,22 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.13.3" + "source": "https://github.com/doctrine/orm/tree/2.13.4" }, - "time": "2022-10-07T06:37:17+00:00" + "time": "2022-11-20T18:53:31+00:00" }, { "name": "doctrine/persistence", - "version": "3.0.4", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "05612da375f8a3931161f435f91d6704926e6ec5" + "reference": "2a9c70a5e21f8968c5a46b79f819ea52f322080b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/05612da375f8a3931161f435f91d6704926e6ec5", - "reference": "05612da375f8a3931161f435f91d6704926e6ec5", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/2a9c70a5e21f8968c5a46b79f819ea52f322080b", + "reference": "2a9c70a5e21f8968c5a46b79f819ea52f322080b", "shasum": "" }, "require": { @@ -1635,7 +1635,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.0.4" + "source": "https://github.com/doctrine/persistence/tree/3.1.0" }, "funding": [ { @@ -1651,7 +1651,7 @@ "type": "tidelift" } ], - "time": "2022-10-13T07:34:14+00:00" + "time": "2022-11-18T14:10:19+00:00" }, { "name": "doctrine/sql-formatter", @@ -2155,7 +2155,7 @@ ], "support": { "issues": "https://github.com/florianv/symfony-swap/issues", - "source": "https://github.com/florianv/symfony-swap/tree/master" + "source": "https://github.com/florianv/symfony-swap/tree/v5.4.0" }, "time": "2022-06-13T07:34:25+00:00" }, @@ -2366,16 +2366,16 @@ }, { "name": "imagine/imagine", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/php-imagine/Imagine.git", - "reference": "ae864f26afbf8859ebd2e2b9df92d77ee175dc13" + "reference": "a6e6da93ea0f76aba33b0e8ed1325523c0413da2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/ae864f26afbf8859ebd2e2b9df92d77ee175dc13", - "reference": "ae864f26afbf8859ebd2e2b9df92d77ee175dc13", + "url": "https://api.github.com/repos/php-imagine/Imagine/zipball/a6e6da93ea0f76aba33b0e8ed1325523c0413da2", + "reference": "a6e6da93ea0f76aba33b0e8ed1325523c0413da2", "shasum": "" }, "require": { @@ -2422,9 +2422,9 @@ ], "support": { "issues": "https://github.com/php-imagine/Imagine/issues", - "source": "https://github.com/php-imagine/Imagine/tree/1.3.2" + "source": "https://github.com/php-imagine/Imagine/tree/1.3.3" }, - "time": "2022-04-01T11:58:30+00:00" + "time": "2022-11-16T13:09:11+00:00" }, { "name": "jbtronics/2fa-webauthn", @@ -2485,16 +2485,16 @@ }, { "name": "laminas/laminas-code", - "version": "4.7.0", + "version": "4.7.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-code.git", - "reference": "0337d9265bc2e6376babad8c511500821620cb30" + "reference": "91aabc066d5620428120800c0eafc0411e441a62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-code/zipball/0337d9265bc2e6376babad8c511500821620cb30", - "reference": "0337d9265bc2e6376babad8c511500821620cb30", + "url": "https://api.github.com/repos/laminas/laminas-code/zipball/91aabc066d5620428120800c0eafc0411e441a62", + "reference": "91aabc066d5620428120800c0eafc0411e441a62", "shasum": "" }, "require": { @@ -2547,7 +2547,7 @@ "type": "community_bridge" } ], - "time": "2022-09-13T10:33:30+00:00" + "time": "2022-11-21T01:32:31+00:00" }, { "name": "lcobucci/clock", @@ -3344,16 +3344,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.1", + "version": "v4.15.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900" + "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", + "reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc", "shasum": "" }, "require": { @@ -3394,9 +3394,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2" }, - "time": "2022-09-04T07:30:47+00:00" + "time": "2022-11-12T15:38:23+00:00" }, { "name": "nikolaposa/version", @@ -8492,16 +8492,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { @@ -8516,7 +8516,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8554,7 +8554,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -8570,20 +8570,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "433d05519ce6990bf3530fba6957499d327395c2" + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2", - "reference": "433d05519ce6990bf3530fba6957499d327395c2", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", "shasum": "" }, "require": { @@ -8595,7 +8595,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8635,7 +8635,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" }, "funding": [ { @@ -8651,20 +8651,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "e407643d610e5f2c8a4b14189150f68934bf5e48" + "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/e407643d610e5f2c8a4b14189150f68934bf5e48", - "reference": "e407643d610e5f2c8a4b14189150f68934bf5e48", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/a3d9148e2c363588e05abbdd4ee4f971f0a5330c", + "reference": "a3d9148e2c363588e05abbdd4ee4f971f0a5330c", "shasum": "" }, "require": { @@ -8676,7 +8676,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8722,7 +8722,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-icu/tree/v1.27.0" }, "funding": [ { @@ -8738,20 +8738,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", - "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8" + "reference": "639084e360537a19f9ee352433b84ce831f3d2da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8", - "reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da", + "reference": "639084e360537a19f9ee352433b84ce831f3d2da", "shasum": "" }, "require": { @@ -8765,7 +8765,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8809,7 +8809,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0" }, "funding": [ { @@ -8825,20 +8825,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd" + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd", - "reference": "219aa369ceff116e673852dce47c3a41794c14bd", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", "shasum": "" }, "require": { @@ -8850,7 +8850,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8893,7 +8893,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" }, "funding": [ { @@ -8909,20 +8909,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", "shasum": "" }, "require": { @@ -8937,7 +8937,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -8976,7 +8976,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" }, "funding": [ { @@ -8992,20 +8992,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2" + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2", - "reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97", + "reference": "869329b1e9894268a8a61dabb69153029b7a8c97", "shasum": "" }, "require": { @@ -9014,7 +9014,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -9052,7 +9052,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0" }, "funding": [ { @@ -9068,20 +9068,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", "shasum": "" }, "require": { @@ -9090,7 +9090,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -9131,7 +9131,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" }, "funding": [ { @@ -9147,20 +9147,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", "shasum": "" }, "require": { @@ -9169,7 +9169,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -9214,7 +9214,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" }, "funding": [ { @@ -9230,20 +9230,20 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.26.0", + "version": "v1.27.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1" + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1", - "reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", "shasum": "" }, "require": { @@ -9252,7 +9252,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.26-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -9293,7 +9293,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0" }, "funding": [ { @@ -9309,7 +9309,7 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { "name": "symfony/process", @@ -13202,16 +13202,16 @@ }, { "name": "composer/pcre", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb" + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", - "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", + "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "shasum": "" }, "require": { @@ -13253,7 +13253,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.0.2" + "source": "https://github.com/composer/pcre/tree/3.1.0" }, "funding": [ { @@ -13269,7 +13269,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T20:24:16+00:00" + "time": "2022-11-17T09:50:14+00:00" }, { "name": "composer/semver", @@ -14003,16 +14003,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f" + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f", - "reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d6fdf01c53978b6429f1393ba4afeca39cc68afa", + "reference": "d6fdf01c53978b6429f1393ba4afeca39cc68afa", "shasum": "" }, "require": { @@ -14042,7 +14042,7 @@ ], "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.9.1" + "source": "https://github.com/phpstan/phpstan/tree/1.9.2" }, "funding": [ { @@ -14058,20 +14058,20 @@ "type": "tidelift" } ], - "time": "2022-11-04T13:35:59+00:00" + "time": "2022-11-10T09:56:11+00:00" }, { "name": "phpstan/phpstan-doctrine", - "version": "1.3.22", + "version": "1.3.23", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-doctrine.git", - "reference": "5080276a271a4ef71fbe33f4fb68f181dffeb03d" + "reference": "964caf844c89134e5c2f19e97cbf8b5d12193779" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/5080276a271a4ef71fbe33f4fb68f181dffeb03d", - "reference": "5080276a271a4ef71fbe33f4fb68f181dffeb03d", + "url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/964caf844c89134e5c2f19e97cbf8b5d12193779", + "reference": "964caf844c89134e5c2f19e97cbf8b5d12193779", "shasum": "" }, "require": { @@ -14125,9 +14125,9 @@ "description": "Doctrine extensions for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-doctrine/issues", - "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.22" + "source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.23" }, - "time": "2022-11-03T15:13:13+00:00" + "time": "2022-11-14T07:46:16+00:00" }, { "name": "phpstan/phpstan-symfony", @@ -14271,12 +14271,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "964c5d9ca40d0ec72db203b3dd6382a30abef616" + "reference": "0399700d159e09b16645945758b65b921d3491fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/964c5d9ca40d0ec72db203b3dd6382a30abef616", - "reference": "964c5d9ca40d0ec72db203b3dd6382a30abef616", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0399700d159e09b16645945758b65b921d3491fe", + "reference": "0399700d159e09b16645945758b65b921d3491fe", "shasum": "" }, "conflict": { @@ -14300,6 +14300,7 @@ "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": ">=3,<3.2.1", + "backdrop/backdrop": "<=1.23", "badaso/core": "<2.6.1", "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", @@ -14333,7 +14334,7 @@ "codeigniter4/shield": "= 1.0.0-beta", "codiad/codiad": "<=2.8.4", "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", - "concrete5/concrete5": "<9", + "concrete5/concrete5": "<9.1.3|>= 9.0.0RC1, < 9.1.3", "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3", @@ -14359,7 +14360,7 @@ "doctrine/mongodb-odm": ">=1,<1.0.2", "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<16|= 12.0.5|>= 3.3.beta1, < 13.0.2", + "dolibarr/dolibarr": "<16|>=16.0.1,<16.0.3|= 12.0.5|>= 3.3.beta1, < 13.0.2", "dompdf/dompdf": "<2.0.1", "drupal/core": ">=7,<7.91|>=8,<9.3.19|>=9.4,<9.4.3", "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", @@ -14379,16 +14380,17 @@ "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.27", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.26", "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.19", + "ezsystems/ezplatform-graphql": ">=1-rc.1,<1.0.13|>=2-beta.1,<2.3.12", + "ezsystems/ezplatform-kernel": "<=1.2.5|>=1.3,<1.3.26", "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", "ezsystems/ezplatform-richtext": ">=2.3,<=2.3.7", "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.29", + "ezsystems/ezpublish-kernel": "<=6.13.8.1|>=7,<7.5.30", "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.3.5.1", "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1|>=2.5,<2.5.15", "ezyang/htmlpurifier": "<4.1.1", "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", "facturascripts/facturascripts": "<=2022.8", @@ -14397,7 +14399,7 @@ "fenom/fenom": "<=2.12.1", "filegator/filegator": "<7.8", "firebase/php-jwt": "<2", - "flarum/core": ">=1,<=1.0.1", + "flarum/core": ">=1,<=1.0.1|>=1.5,<1.6.2", "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", "fluidtypo3/vhs": "<5.1.1", @@ -14434,7 +14436,9 @@ "hjue/justwriting": "<=1", "hov/jobfair": "<1.0.13|>=2,<2.0.2", "hyn/multi-tenant": ">=5.6,<5.7.2", - "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4", + "ibexa/admin-ui": ">=4.2,<4.2.3", + "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3", + "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", "ibexa/post-install": "<=1.0.4", "icecoder/icecoder": "<=8.1", "idno/known": "<=1.3.1", @@ -14451,6 +14455,7 @@ "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", "james-heinrich/getid3": "<1.9.21", + "jasig/phpcas": "<1.3.3", "joomla/archive": "<1.1.12|>=2,<2.0.1", "joomla/filesystem": "<1.6.2|>=2,<2.0.1", "joomla/filter": "<1.4.4|>=2,<2.0.1", @@ -14478,7 +14483,7 @@ "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<=22.8", + "librenms/librenms": "<22.10", "limesurvey/limesurvey": "<3.27.19", "livehelperchat/livehelperchat": "<=3.91", "livewire/livewire": ">2.2.4,<2.2.6", @@ -14503,7 +14508,7 @@ "modx/revolution": "<= 2.8.3-pl|<2.8", "mojo42/jirafeau": "<4.4", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.0.1", + "moodle/moodle": "<4.0.5", "mustache/mustache": ">=2,<2.14.1", "namshi/jose": "<2.2", "neoan3-apps/template": "<1.1.1", @@ -14603,12 +14608,12 @@ "shopware/storefront": "<=6.4.8.1", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", - "silverstripe/admin": ">=1,<1.8.1", - "silverstripe/assets": ">=1,<1.10.1", - "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", + "silverstripe/admin": ">=1,<1.11.3", + "silverstripe/assets": ">=1,<1.11.1", + "silverstripe/cms": "<4.11.3", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.10.9", + "silverstripe/framework": "<4.11.14", "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|= 4.0.0-alpha1", "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", @@ -14617,6 +14622,7 @@ "silverstripe/subsites": ">=2,<2.1.1", "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", "silverstripe/userforms": "<3", + "silverstripe/versioned-admin": ">=1,<1.11.1", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", "simplesamlphp/simplesamlphp": "<1.18.6", @@ -14691,7 +14697,7 @@ "topthink/framework": "<=6.0.13", "topthink/think": "<=6.0.9", "topthink/thinkphp": "<=3.2.3", - "tribalsystems/zenario": "<9.2.55826", + "tribalsystems/zenario": "<=9.3.57186", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.32|>=11,<11.5.16", @@ -14727,7 +14733,7 @@ "yetiforce/yetiforce-crm": "<=6.4", "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": ">=1.1.14,<1.1.15", + "yiisoft/yii": "<1.1.27", "yiisoft/yii2": "<2.0.38", "yiisoft/yii2-bootstrap": "<2.0.4", "yiisoft/yii2-dev": "<2.0.43", @@ -14798,7 +14804,7 @@ "type": "tidelift" } ], - "time": "2022-11-04T21:04:09+00:00" + "time": "2022-11-23T23:04:03+00:00" }, { "name": "sebastian/diff", @@ -15348,16 +15354,16 @@ }, { "name": "symplify/easy-coding-standard", - "version": "11.1.16", + "version": "11.1.17", "source": { "type": "git", "url": "https://github.com/symplify/easy-coding-standard.git", - "reference": "32ebd57f0f47713540df8ea39134adaa9d912fae" + "reference": "2a98e5b976a3ab573d8e5604d6eb39d9f5783760" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/32ebd57f0f47713540df8ea39134adaa9d912fae", - "reference": "32ebd57f0f47713540df8ea39134adaa9d912fae", + "url": "https://api.github.com/repos/symplify/easy-coding-standard/zipball/2a98e5b976a3ab573d8e5604d6eb39d9f5783760", + "reference": "2a98e5b976a3ab573d8e5604d6eb39d9f5783760", "shasum": "" }, "require": { @@ -15387,7 +15393,7 @@ ], "description": "Prefixed scoped version of ECS package", "support": { - "source": "https://github.com/symplify/easy-coding-standard/tree/11.1.16" + "source": "https://github.com/symplify/easy-coding-standard/tree/11.1.17" }, "funding": [ { @@ -15399,7 +15405,7 @@ "type": "github" } ], - "time": "2022-10-27T10:48:13+00:00" + "time": "2022-11-10T15:20:49+00:00" }, { "name": "vimeo/psalm", diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 44ea77f3..f1435e9d 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -13,7 +13,7 @@ doctrine: class: App\Helpers\UTCDateTimeType big_decimal: class: App\Helpers\BigDecimalType - + schema_filter: ~^(?!internal)~ # Only enable this when needed profiling_collect_backtrace: false diff --git a/config/permissions.yaml b/config/permissions.yaml index 528ea61e..27cb5a06 100644 --- a/config/permissions.yaml +++ b/config/permissions.yaml @@ -2,10 +2,12 @@ # This should be compatible with the legacy Part-DB groups: - parts: - label: "perm.group.parts" - structures: - label: "perm.group.structures" + #parts: + # label: "perm.group.parts" + #structures: + # label: "perm.group.structures" + data: + label: "perm.group.data" system: label: "perm.group.system" @@ -15,221 +17,52 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co # Part related permissions parts: # e.g. this maps to perms_parts in User/Group database - group: "parts" + group: "data" label: "perm.parts" operations: # Here are all possible operations are listed => the op name is mapped to bit value read: label: "perm.read" - bit: 0 + # If a part can be read by a user, he can also see all the datastructures (except devices) + alsoSet: ['storelocations.read', 'footprints.read', 'categories.read', 'suppliers.read', 'manufacturers.read', + 'currencies.read', 'attachment_types.read', 'measurement_units.read'] edit: label: "perm.edit" - bit: 2 alsoSet: 'read' create: label: "perm.create" - bit: 4 alsoSet: ['read', 'edit'] - #move: - # label: "perm.part.move" - # bit: 6 - # alsoSet: 'read' delete: label: "perm.delete" - bit: 8 alsoSet: ['read', 'edit'] - search: - label: "perm.part.search" - bit: 10 - all_parts: - label: "perm.part.all_parts" - bit: 12 - no_price_parts: - label: "perm.part.no_price_parts" - bit: 14 - obsolete_parts: - label: "perm.part.obsolete_parts" - bit: 16 - unknown_instock_parts: - label: "perm.part.unknown_instock_parts" - bit: 18 change_favorite: label: "perm.part.change_favorite" - bit: 20 - show_favorite_parts: - label: "perm.part.show_favorite" - bit: 24 - show_last_edit_parts: - label: "perm.part.show_last_edit_parts" - bit: 26 - show_users: - label: "perm.part.show_users" - bit: 28 + alsoSet: ['edit'] show_history: label: "perm.part.show_history" - bit: 30 + alsoSet: ['read'] revert_element: label: "perm.revert_elements" - bit: 32 alsoSet: ["read", "edit", "create", "delete", "show_history"] - parts_name: &PART_ATTRIBUTE # We define a template here, that we can use for all part attributes. - label: "perm.part.name" - group: "parts" - operations: - read: - label: "perm.read" - bit: 0 - edit: - label: "perm.edit" - bit: 2 - alsoSet: 'read' - - parts_category: - <<: *PART_ATTRIBUTE - label: "perm.part.category" - - parts_description: - <<: *PART_ATTRIBUTE - label: "perm.part.description" - - parts_minamount: - <<: *PART_ATTRIBUTE - label: "perm.part.minamount" - - parts_footprint: - <<: *PART_ATTRIBUTE - label: "perm.part.footprint" - - parts_comment: - <<: *PART_ATTRIBUTE - label: "perm.part.comment" - - parts_manufacturer: - <<: *PART_ATTRIBUTE - label: "perm.part.manufacturer" - - parts_mpn: - <<: *PART_ATTRIBUTE - label: "perm.part.mpn" - - parts_status: - <<: *PART_ATTRIBUTE - label: "perm.part.status" - - parts_tags: - <<: *PART_ATTRIBUTE - label: "perm.part.tags" - - parts_unit: - <<: *PART_ATTRIBUTE - label: "perm.part.unit" - - parts_mass: - <<: *PART_ATTRIBUTE - label: "perm.part.mass" - - parts_orderdetails: &PART_MULTI_ATTRIBUTE - label: "perm.part.orderdetails" - group: "parts" - operations: - read: - label: "perm.read" - bit: 0 - edit: - label: "perm.edit" - bit: 2 - alsoSet: 'read' - create: - label: "perm.create" - bit: 4 - alsoSet: ['read', 'edit'] - delete: - label: "perm.delete" - bit: 6 - alsoSet: ['read'] - - - parts_prices: - <<: *PART_MULTI_ATTRIBUTE - label: "perm.part.prices" - - parts_parameters: - <<: *PART_MULTI_ATTRIBUTE - label: "perm.part.parameters" - - parts_lots: - <<: *PART_MULTI_ATTRIBUTE - label: "perm.part.lots" - - parts_attachments: - group: "structures" - label: "perm.part.attachments" - operations: - read: - label: "perm.read" - bit: 0 - edit: - label: "perm.edit" - bit: 2 - alsoSet: 'read' - create: - label: "perm.create" - bit: 4 - alsoSet: ['read', 'edit'] - delete: - label: "perm.delete" - bit: 6 - alsoSet: ['read'] - show_history: - label: "perm.show_history" - bit: 8 - revert_element: - label: "perm.revert_elements" - bit: 10 - alsoSet: ["read", "edit", "create", "delete", "show_history"] - show_private: - label: "perm.attachment_show_private" - bit: 12 - alsoSet: ["read"] - - parts_order: - <<: *PART_ATTRIBUTE - label: "perm.part.order" - storelocations: &PART_CONTAINING label: "perm.storelocations" - group: "structures" + group: "data" operations: read: label: "perm.read" - bit: 0 edit: label: "perm.edit" - bit: 2 alsoSet: 'read' create: label: "perm.create" - bit: 4 alsoSet: ['read', 'edit'] - move: - label: "perm.move" - bit: 6 delete: label: "perm.delete" - bit: 8 alsoSet: ['read', 'edit'] - list_parts: - label: "perm.list_parts" - bit: 10 - show_users: - label: "perm.show_users" - bit: 12 show_history: label: "perm.show_history" - bit: 14 revert_element: label: "perm.revert_elements" - bit: 16 alsoSet: ["read", "edit", "create", "delete", "show_history"] footprints: @@ -267,36 +100,24 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co tools: label: "perm.part.tools" operations: - import: - label: "perm.tools.import" - bit: 0 - labels: - label: "perm.tools.labels" - bit: 2 + #import: + # label: "perm.tools.import" + #labels: + # label: "perm.tools.labels" #calculator: # label: "perm.tools.calculator" - # bit: 4 #footprints: # label: "perm.tools.footprints" - # bit: 6 #ic_logos: # label: "perm.tools.ic_logos" - # bit: 8 statistics: label: "perm.tools.statistics" - bit: 10 lastActivity: label: "perm.tools.lastActivity" - bit: 12 - timetravel: - label: "perm.tools.timeTravel" - bit: 14 label_scanner: label: "perm.tools.label_scanner" - bit: 16 reel_calculator: label: "perm.tools.reel_calculator" - bit: 18 groups: label: "perm.groups" @@ -304,33 +125,23 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: read: label: "perm.read" - bit: 0 edit: label: "perm.edit" - bit: 2 alsoSet: 'read' create: label: "perm.create" - bit: 4 alsoSet: ['read', 'edit'] - move: - label: "perm.move" - bit: 6 delete: label: "perm.delete" - bit: 8 alsoSet: ['read', 'delete'] edit_permissions: label: "perm.edit_permissions" alsoSet: ['read', 'edit'] - bit: 10 show_history: label: "perm.show_history" - bit: 12 revert_element: label: "perm.revert_elements" - bit: 14 - alsoSet: ["read", "edit", "create", "delete", "move", "edit_permissions", "show_history"] + alsoSet: ["read", "edit", "create", "delete", "edit_permissions", "show_history"] users: label: "perm.users" @@ -338,167 +149,119 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co operations: read: label: "perm.read" - bit: 0 create: label: "perm.create" alsoSet: ['read', 'edit_username', 'edit_infos'] - bit: 4 delete: label: "perm.delete" alsoSet: ['read', 'edit_username', 'edit_infos'] - bit: 8 edit_username: label: "perm.users.edit_user_name" alsoSet: ['read'] - bit: 2 - change_group: - label: "perm.users.edit_change_group" - alsoSet: 'read' - bit: 6 edit_infos: label: "perm.users.edit_infos" alsoSet: 'read' - bit: 10 edit_permissions: label: "perm.users.edit_permissions" alsoSet: 'read' - bit: 12 set_password: label: "perm.users.set_password" alsoSet: 'read' - bit: 14 change_user_settings: label: "perm.users.change_user_settings" - bit: 16 show_history: label: "perm.show_history" - bit: 18 revert_element: label: "perm.revert_elements" - bit: 20 - alsoSet: ["read", "create", "delete", "edit_permissions", "show_history", "edit_infos", "change_group", "edit_username"] + alsoSet: ["read", "create", "delete", "edit_permissions", "show_history", "edit_infos", "edit_username"] - database: - label: "perm.database" - group: "system" - operations: - see_status: - label: "perm.database.see_status" - bit: 0 - update_db: - label: "perm.database.update_db" - bit: 2 - alsoSet: 'see_status' - read_db_settings: - label: "perm.database.read_db_settings" - bit: 4 - write_db_settings: - label: "perm.database.write_db_settings" - alsoSet: ['read_db_settings', 'see_status'] - bit: 2 + #database: + # label: "perm.database" + # group: "system" + # operations: + # see_status: + # label: "perm.database.see_status" + # update_db: + # label: "perm.database.update_db" + # alsoSet: 'see_status' + # read_db_settings: + # label: "perm.database.read_db_settings" + # write_db_settings: + # label: "perm.database.write_db_settings" + # alsoSet: ['read_db_settings', 'see_status'] - config: - label: "perm.config" - group: "system" - operations: - read_config: - label: "perm.config.read_config" - bit: 0 - edit_config: - label: "perm.config.edit_config" - alsoSet: 'read_config' - bit: 2 - server_info: - label: "perm.config.server_info" - bit: 6 + #config: + # label: "perm.config" + # group: "system" + # operations: + # read_config: + # label: "perm.config.read_config" + # edit_config: + # label: "perm.config.edit_config" + # alsoSet: 'read_config' + # server_info: + # label: "perm.config.server_info" system: label: "perm.system" group: "system" operations: - use_debug: - label: "perm.config.use_debug" - bit: 0 show_logs: label: "perm.show_logs" - bit: 2 delete_logs: label: "perm.delete_logs" alsoSet: 'show_logs' - bit: 4 + server_infos: + label: "perm.server_infos" - devices_parts: - label: "perm.device_parts" - group: "parts" + attachments: + label: "perm.part.attachments" operations: - read: - label: "perm.read" - bit: 0 - edit: - label: "perm.edit" - alsoSet: 'read' - bit: 2 - create: - label: "perm.create" - alsoSet: ['edit', 'read'] - bit: 6 - delete: - label: "perm.delete" - alsoSet: ['edit', 'read'] - bit: 8 + show_private: + label: "perm.attachments.show_private" + list_attachments: + label: "perm.attachments.list_attachments" + alsoSet: ['attachment_types.read'] self: label: "perm.self" operations: edit_infos: label: "perm.self.edit_infos" - bit: 0 edit_username: label: "perm.self.edit_username" - bit: 2 show_permissions: label: "perm.self.show_permissions" - bit: 4 show_logs: label: "perm.self.show_logs" - bit: 6 labels: label: "perm.labels" operations: create_labels: label: "perm.self.create_labels" - bit: 0 edit_options: label: "perm.self.edit_options" - bit: 2 alsoSet: ['create_labels'] read_profiles: label: "perm.self.read_profiles" - bit: 10 edit_profiles: label: "perm.self.edit_profiles" - bit: 6 alsoSet: ['read_profiles'] create_profiles: label: "perm.self.create_profiles" - bit: 8 alsoSet: ['read_profiles', 'edit_profiles'] delete_profiles: label: "perm.self.delete_profiles" - bit: 4 alsoSet: ['read_profiles', 'edit_profiles', 'create_profiles'] use_twig: label: "perm.labels.use_twig" - bit: 12 alsoSet: ['create_labels', 'edit_options'] show_history: label: "perm.show_history" - bit: 14 alsoSet: ['read_profiles'] revert_element: label: "perm.revert_elements" - bit: 16 alsoSet: ['read_profiles', 'edit_profiles', 'create_profiles', 'delete_profiles'] diff --git a/config/services.yaml b/config/services.yaml index 449519b8..9ebf3079 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -127,10 +127,6 @@ services: # Security #################################################################################################################### - App\Security\EntityListeners\ElementPermissionListener: - tags: - - { name: "doctrine.orm.entity_listener" } - #################################################################################################################### # Cache #################################################################################################################### @@ -177,7 +173,7 @@ services: arguments: $allow_email_pw_reset: '%partdb.users.email_pw_reset%' - App\Services\TFA\BackupCodeGenerator: + App\Services\UserSystem\TFA\BackupCodeGenerator: arguments: $code_length: 8 $code_count: 15 diff --git a/migrations/Version20221114193325.php b/migrations/Version20221114193325.php new file mode 100644 index 00000000..ba66fbc5 --- /dev/null +++ b/migrations/Version20221114193325.php @@ -0,0 +1,127 @@ +addSql(<<<'SQL' + UPDATE `groups` SET permissions_data = '{"parts":{"read":true,"edit":true,"create":true,"delete":true,"change_favorite":true,"show_history":true,"revert_element":true},"tools":{"statistics":true,"label_scanner":true,"reel_calculator":true,"lastActivity":true},"attachments":{"list_attachments":true,"show_private":true},"self":{"show_permissions":true,"edit_infos":true},"labels":{"create_labels":true,"edit_options":true,"read_profiles":true,"edit_profiles":true,"create_profiles":true,"delete_profiles":true,"show_history":true,"revert_element":true},"categories":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"storelocations":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"footprints":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"manufacturers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"attachment_types":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"currencies":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"measurement_units":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"suppliers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"users":{"read":true,"create":true,"delete":true,"edit_username":true,"edit_infos":true,"edit_permissions":true,"set_password":true,"change_user_settings":true,"show_history":true,"revert_element":true},"groups":{"read":true,"edit":true,"create":true,"delete":true,"edit_permissions":true,"show_history":true,"revert_element":true},"system":{"show_logs":true,"server_infos":true},"devices":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true}}' + WHERE id = 1 AND name = 'admins'; + SQL); + $this->addSql(<<<'SQL' + UPDATE `groups` SET permissions_data = '{"parts":{"read":true},"tools":{"statistics":true,"label_scanner":true,"reel_calculator":true},"attachments":{"list_attachments":true},"self":{"show_permissions":true},"labels":{"create_labels":true,"edit_options":true},"storelocations":{"read":true},"footprints":{"read":true},"categories":{"read":true},"suppliers":{"read":true},"manufacturers":{"read":true},"currencies":{"read":true},"attachment_types":{"read":true},"measurement_units":{"read":true},"devices":{"read":true}}' + WHERE id = 2 AND name = 'readonly'; + SQL); + $this->addSql(<<<'SQL' + UPDATE `groups` SET permissions_data = '{"parts":{"read":true,"edit":true,"create":true,"delete":true,"change_favorite":true,"show_history":true,"revert_element":true},"tools":{"statistics":true,"label_scanner":true,"reel_calculator":true,"lastActivity":true},"attachments":{"list_attachments":true,"show_private":true},"self":{"show_permissions":true,"edit_infos":true},"labels":{"create_labels":true,"edit_options":true,"read_profiles":true,"edit_profiles":true,"create_profiles":true,"delete_profiles":true,"show_history":true,"revert_element":true},"categories":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"storelocations":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"footprints":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"manufacturers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"attachment_types":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"currencies":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"measurement_units":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"suppliers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"devices":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true}}' + WHERE id = 3 AND name = 'users'; + SQL); + + //Disable login of all users with ID > 2 (meaning all except the anonymous and admin user) + $this->addSql(<<<'SQL' + UPDATE `users` SET disabled = 1 + WHERE id > 2; + SQL); + + //Reset the permissions of the admin user, to allow admin permissions (like the admins group) + $this->addSql(<<<'SQL' + UPDATE `users` SET permissions_data = '{"parts":{"read":true,"edit":true,"create":true,"delete":true,"change_favorite":true,"show_history":true,"revert_element":true},"tools":{"statistics":true,"label_scanner":true,"reel_calculator":true,"lastActivity":true},"attachments":{"list_attachments":true,"show_private":true},"self":{"show_permissions":true,"edit_infos":true},"labels":{"create_labels":true,"edit_options":true,"read_profiles":true,"edit_profiles":true,"create_profiles":true,"delete_profiles":true,"show_history":true,"revert_element":true},"categories":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"storelocations":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"footprints":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"manufacturers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"attachment_types":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"currencies":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"measurement_units":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"suppliers":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true},"users":{"read":true,"create":true,"delete":true,"edit_username":true,"edit_infos":true,"edit_permissions":true,"set_password":true,"change_user_settings":true,"show_history":true,"revert_element":true},"groups":{"read":true,"edit":true,"create":true,"delete":true,"edit_permissions":true,"show_history":true,"revert_element":true},"system":{"show_logs":true,"server_infos":true},"devices":{"read":true,"edit":true,"create":true,"delete":true,"show_history":true,"revert_element":true}}' + WHERE id = 2; + SQL); + + + $this->warnIf(true, "\x1b[1;37;43m\n!!! All permissions were reset! Please change them to the desired state, immediately !!!\x1b[0;39;49m"); + $this->warnIf(true, "\x1b[1;37;43m\n!!! For security reasons all users (except the admin user) were disabled. Login with admin user and reenable other users after checking their permissions !!!\x1b[0;39;49m"); + $this->warnIf(true, "\x1b[1;37;43m\n!!! For more infos see: https://github.com/Part-DB/Part-DB-symfony/discussions/193 !!!\x1b[0;39;49m"); + } + + public function mySQLUp(Schema $schema): void + { + $this->addSql('ALTER TABLE groups ADD permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', DROP perms_system, DROP perms_groups, DROP perms_users, DROP perms_self, DROP perms_system_config, DROP perms_system_database, DROP perms_parts, DROP perms_parts_name, DROP perms_parts_description, DROP perms_parts_footprint, DROP perms_parts_manufacturer, DROP perms_parts_comment, DROP perms_parts_order, DROP perms_parts_orderdetails, DROP perms_parts_prices, DROP perms_parts_attachements, DROP perms_devices, DROP perms_devices_parts, DROP perms_storelocations, DROP perms_footprints, DROP perms_categories, DROP perms_suppliers, DROP perms_manufacturers, DROP perms_attachement_types, DROP perms_tools, DROP perms_labels, DROP perms_parts_category, DROP perms_parts_minamount, DROP perms_parts_lots, DROP perms_parts_tags, DROP perms_parts_unit, DROP perms_parts_mass, DROP perms_parts_status, DROP perms_parts_mpn, DROP perms_currencies, DROP perms_measurement_units, DROP perms_parts_parameters'); + $this->addSql('ALTER TABLE users ADD permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', DROP perms_system, DROP perms_groups, DROP perms_users, DROP perms_self, DROP perms_system_config, DROP perms_system_database, DROP perms_parts, DROP perms_parts_name, DROP perms_parts_description, DROP perms_parts_footprint, DROP perms_parts_manufacturer, DROP perms_parts_comment, DROP perms_parts_order, DROP perms_parts_orderdetails, DROP perms_parts_prices, DROP perms_parts_attachements, DROP perms_devices, DROP perms_devices_parts, DROP perms_storelocations, DROP perms_footprints, DROP perms_categories, DROP perms_suppliers, DROP perms_manufacturers, DROP perms_attachement_types, DROP perms_tools, DROP perms_labels, DROP perms_parts_category, DROP perms_parts_minamount, DROP perms_parts_lots, DROP perms_parts_tags, DROP perms_parts_unit, DROP perms_parts_mass, DROP perms_parts_status, DROP perms_parts_mpn, DROP perms_currencies, DROP perms_measurement_units, DROP perms_parts_parameters'); + + $this->addDataMigrationAndWarning(); + } + + public function mySQLDown(Schema $schema): void + { + $this->addSql('ALTER TABLE `groups` ADD perms_system INT NOT NULL, ADD perms_groups INT NOT NULL, ADD perms_users INT NOT NULL, ADD perms_self INT NOT NULL, ADD perms_system_config INT NOT NULL, ADD perms_system_database INT NOT NULL, ADD perms_parts BIGINT NOT NULL, ADD perms_parts_name SMALLINT NOT NULL, ADD perms_parts_description SMALLINT NOT NULL, ADD perms_parts_footprint SMALLINT NOT NULL, ADD perms_parts_manufacturer SMALLINT NOT NULL, ADD perms_parts_comment SMALLINT NOT NULL, ADD perms_parts_order SMALLINT NOT NULL, ADD perms_parts_orderdetails SMALLINT NOT NULL, ADD perms_parts_prices SMALLINT NOT NULL, ADD perms_parts_attachements SMALLINT NOT NULL, ADD perms_devices INT NOT NULL, ADD perms_devices_parts INT NOT NULL, ADD perms_storelocations INT NOT NULL, ADD perms_footprints INT NOT NULL, ADD perms_categories INT NOT NULL, ADD perms_suppliers INT NOT NULL, ADD perms_manufacturers INT NOT NULL, ADD perms_attachement_types INT NOT NULL, ADD perms_tools INT NOT NULL, ADD perms_labels INT NOT NULL, ADD perms_parts_category SMALLINT NOT NULL, ADD perms_parts_minamount SMALLINT NOT NULL, ADD perms_parts_lots SMALLINT NOT NULL, ADD perms_parts_tags SMALLINT NOT NULL, ADD perms_parts_unit SMALLINT NOT NULL, ADD perms_parts_mass SMALLINT NOT NULL, ADD perms_parts_status SMALLINT NOT NULL, ADD perms_parts_mpn SMALLINT NOT NULL, ADD perms_currencies INT NOT NULL, ADD perms_measurement_units INT NOT NULL, ADD perms_parts_parameters SMALLINT NOT NULL, DROP permissions_data'); + $this->addSql('ALTER TABLE `users` ADD perms_system INT NOT NULL, ADD perms_groups INT NOT NULL, ADD perms_users INT NOT NULL, ADD perms_self INT NOT NULL, ADD perms_system_config INT NOT NULL, ADD perms_system_database INT NOT NULL, ADD perms_parts BIGINT NOT NULL, ADD perms_parts_name SMALLINT NOT NULL, ADD perms_parts_description SMALLINT NOT NULL, ADD perms_parts_footprint SMALLINT NOT NULL, ADD perms_parts_manufacturer SMALLINT NOT NULL, ADD perms_parts_comment SMALLINT NOT NULL, ADD perms_parts_order SMALLINT NOT NULL, ADD perms_parts_orderdetails SMALLINT NOT NULL, ADD perms_parts_prices SMALLINT NOT NULL, ADD perms_parts_attachements SMALLINT NOT NULL, ADD perms_devices INT NOT NULL, ADD perms_devices_parts INT NOT NULL, ADD perms_storelocations INT NOT NULL, ADD perms_footprints INT NOT NULL, ADD perms_categories INT NOT NULL, ADD perms_suppliers INT NOT NULL, ADD perms_manufacturers INT NOT NULL, ADD perms_attachement_types INT NOT NULL, ADD perms_tools INT NOT NULL, ADD perms_labels INT NOT NULL, ADD perms_parts_category SMALLINT NOT NULL, ADD perms_parts_minamount SMALLINT NOT NULL, ADD perms_parts_lots SMALLINT NOT NULL, ADD perms_parts_tags SMALLINT NOT NULL, ADD perms_parts_unit SMALLINT NOT NULL, ADD perms_parts_mass SMALLINT NOT NULL, ADD perms_parts_status SMALLINT NOT NULL, ADD perms_parts_mpn SMALLINT NOT NULL, ADD perms_currencies INT NOT NULL, ADD perms_measurement_units INT NOT NULL, ADD perms_parts_parameters SMALLINT NOT NULL, DROP permissions_data'); + + } + + public function sqLiteUp(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added FROM groups'); + $this->addSql('DROP TABLE groups'); + $this->addSql('CREATE TABLE groups (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachement INTEGER DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB DEFAULT \'[]\' NOT NULL --(DC2Type:json) + , CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D39706DEDCEC2 FOREIGN KEY (id_preview_attachement) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO groups (id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added FROM __temp__groups'); + $this->addSql('DROP TABLE __temp__groups'); + $this->addSql('CREATE INDEX group_idx_parent_name ON groups (parent_id, name)'); + $this->addSql('CREATE INDEX group_idx_name ON groups (name)'); + $this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON groups (parent_id)'); + $this->addSql('CREATE INDEX IDX_F06D39706DEDCEC2 ON groups (id_preview_attachement)'); + $this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added FROM users'); + $this->addSql('DROP TABLE users'); + $this->addSql('CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, id_preview_attachement INTEGER DEFAULT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL --(DC2Type:json) + , google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, name VARCHAR(180) NOT NULL, settings CLOB NOT NULL --(DC2Type:json) + , backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB DEFAULT \'[]\' NOT NULL --(DC2Type:json) + , CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E96DEDCEC2 FOREIGN KEY (id_preview_attachement) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO users (id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added) SELECT id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added FROM __temp__users'); + $this->addSql('DROP TABLE __temp__users'); + $this->addSql('CREATE INDEX user_idx_username ON users (name)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON users (name)'); + $this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON users (group_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON users (currency_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E96DEDCEC2 ON users (id_preview_attachement)'); + + + $this->addDataMigrationAndWarning(); + } + + public function sqLiteDown(Schema $schema): void + { + $this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added FROM "groups"'); + $this->addSql('DROP TABLE "groups"'); + $this->addSql('CREATE TABLE "groups" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachement INTEGER DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, perms_system INTEGER NOT NULL, perms_groups INTEGER NOT NULL, perms_users INTEGER NOT NULL, perms_self INTEGER NOT NULL, perms_system_config INTEGER NOT NULL, perms_system_database INTEGER NOT NULL, perms_parts BIGINT NOT NULL, perms_parts_name SMALLINT NOT NULL, perms_parts_category SMALLINT NOT NULL, perms_parts_description SMALLINT NOT NULL, perms_parts_minamount SMALLINT NOT NULL, perms_parts_footprint SMALLINT NOT NULL, perms_parts_lots SMALLINT NOT NULL, perms_parts_tags SMALLINT NOT NULL, perms_parts_unit SMALLINT NOT NULL, perms_parts_mass SMALLINT NOT NULL, perms_parts_manufacturer SMALLINT NOT NULL, perms_parts_status SMALLINT NOT NULL, perms_parts_mpn SMALLINT NOT NULL, perms_parts_comment SMALLINT NOT NULL, perms_parts_order SMALLINT NOT NULL, perms_parts_orderdetails SMALLINT NOT NULL, perms_parts_prices SMALLINT NOT NULL, perms_parts_parameters SMALLINT NOT NULL, perms_parts_attachements SMALLINT NOT NULL, perms_devices INTEGER NOT NULL, perms_devices_parts INTEGER NOT NULL, perms_storelocations INTEGER NOT NULL, perms_footprints INTEGER NOT NULL, perms_categories INTEGER NOT NULL, perms_suppliers INTEGER NOT NULL, perms_manufacturers INTEGER NOT NULL, perms_attachement_types INTEGER NOT NULL, perms_currencies INTEGER NOT NULL, perms_measurement_units INTEGER NOT NULL, perms_tools INTEGER NOT NULL, perms_labels INTEGER NOT NULL, CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D39706DEDCEC2 FOREIGN KEY (id_preview_attachement) REFERENCES "attachments" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "groups" (id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachement, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added FROM __temp__groups'); + $this->addSql('DROP TABLE __temp__groups'); + $this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON "groups" (parent_id)'); + $this->addSql('CREATE INDEX IDX_F06D39706DEDCEC2 ON "groups" (id_preview_attachement)'); + $this->addSql('CREATE INDEX group_idx_name ON "groups" (name)'); + $this->addSql('CREATE INDEX group_idx_parent_name ON "groups" (parent_id, name)'); + + $this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added FROM "users"'); + $this->addSql('DROP TABLE "users"'); + $this->addSql('CREATE TABLE "users" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, id_preview_attachement INTEGER DEFAULT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL -- +(DC2Type:json) + , google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, name VARCHAR(180) NOT NULL, settings CLOB NOT NULL -- +(DC2Type:json) + , backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, perms_system INTEGER NOT NULL, perms_groups INTEGER NOT NULL, perms_users INTEGER NOT NULL, perms_self INTEGER NOT NULL, perms_system_config INTEGER NOT NULL, perms_system_database INTEGER NOT NULL, perms_parts BIGINT NOT NULL, perms_parts_name SMALLINT NOT NULL, perms_parts_category SMALLINT NOT NULL, perms_parts_description SMALLINT NOT NULL, perms_parts_minamount SMALLINT NOT NULL, perms_parts_footprint SMALLINT NOT NULL, perms_parts_lots SMALLINT NOT NULL, perms_parts_tags SMALLINT NOT NULL, perms_parts_unit SMALLINT NOT NULL, perms_parts_mass SMALLINT NOT NULL, perms_parts_manufacturer SMALLINT NOT NULL, perms_parts_status SMALLINT NOT NULL, perms_parts_mpn SMALLINT NOT NULL, perms_parts_comment SMALLINT NOT NULL, perms_parts_order SMALLINT NOT NULL, perms_parts_orderdetails SMALLINT NOT NULL, perms_parts_prices SMALLINT NOT NULL, perms_parts_parameters SMALLINT NOT NULL, perms_parts_attachements SMALLINT NOT NULL, perms_devices INTEGER NOT NULL, perms_devices_parts INTEGER NOT NULL, perms_storelocations INTEGER NOT NULL, perms_footprints INTEGER NOT NULL, perms_categories INTEGER NOT NULL, perms_suppliers INTEGER NOT NULL, perms_manufacturers INTEGER NOT NULL, perms_attachement_types INTEGER NOT NULL, perms_currencies INTEGER NOT NULL, perms_measurement_units INTEGER NOT NULL, perms_tools INTEGER NOT NULL, perms_labels INTEGER NOT NULL, CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E96DEDCEC2 FOREIGN KEY (id_preview_attachement) REFERENCES "attachments" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)'); + $this->addSql('INSERT INTO "users" (id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added) SELECT id, group_id, currency_id, id_preview_attachement, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added FROM __temp__users'); + $this->addSql('DROP TABLE __temp__users'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON "users" (name)'); + $this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON "users" (group_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E938248176 ON "users" (currency_id)'); + $this->addSql('CREATE INDEX IDX_1483A5E96DEDCEC2 ON "users" (id_preview_attachement)'); + $this->addSql('CREATE INDEX user_idx_username ON "users" (name)'); + } +} diff --git a/src/Command/User/SetPasswordCommand.php b/src/Command/User/SetPasswordCommand.php index f36a2b24..237c6a7b 100644 --- a/src/Command/User/SetPasswordCommand.php +++ b/src/Command/User/SetPasswordCommand.php @@ -56,7 +56,7 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; class SetPasswordCommand extends Command { - protected static $defaultName = 'partdb:users:set-password|app:set-password|users:set-password'; + protected static $defaultName = 'partdb:users:set-password|app:set-password|users:set-password|partdb:user:set-password'; protected EntityManagerInterface $entityManager; protected UserPasswordHasherInterface $encoder; @@ -77,7 +77,6 @@ class SetPasswordCommand extends Command ->setDescription('Sets the password of a user') ->setHelp('This password allows you to set the password of a user, without knowing the old password.') ->addArgument('user', InputArgument::REQUIRED, 'The name of the user') - ; } diff --git a/src/Command/User/UserEnableCommand.php b/src/Command/User/UserEnableCommand.php new file mode 100644 index 00000000..847b5f3e --- /dev/null +++ b/src/Command/User/UserEnableCommand.php @@ -0,0 +1,92 @@ +entityManager = $entityManager; + + parent::__construct($name); + } + + protected function configure(): void + { + $this + ->setDescription('Enables/Disable the login of one or more users') + ->setHelp('This allows you to allow or prevent the login of certain user. Use the --disable option to disable the login for the given users') + ->addArgument('users', InputArgument::IS_ARRAY, 'The usernames of the users to use') + ->addOption('all', 'a', InputOption::VALUE_NONE, 'Enable/Disable all users') + ->addOption('disable', 'd', InputOption::VALUE_NONE, 'Disable the login of the given users') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $usernames = $input->getArgument('users'); + $all_users = $input->getOption('all'); + $disabling = $input->getOption('disable'); + + if(!$all_users && empty($usernames)) { + $io->error('No users given! You have to pass atleast one username or use the --all option to use all users!'); + return self::FAILURE; + } + + $repo = $this->entityManager->getRepository(User::class); + + $users = []; + if($all_users) { //If we requested to change all users at once, then get all users from repo + $users = $repo->findAll(); + } else { //Otherwise, fetch the users from DB + foreach ($usernames as $username) { + $user = $repo->findByEmailOrName($username); + if ($user === null) { + $io->error('No user found with username: '.$username); + return self::FAILURE; + } + $users[] = $user; + } + } + + if ($disabling) { + $io->note('The following users will be disabled:'); + } else { + $io->note('The following users will be enabled:'); + } + $io->table(['Username', 'Enabled/Disabled'], + array_map(function(User $user) { + return [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled']; + }, $users)); + + if(!$io->confirm('Do you want to continue?')) { + $io->warning('Aborting!'); + return self::SUCCESS; + } + + foreach ($users as $user) { + $user->setDisabled($disabling); + } + + //Save the results + $this->entityManager->flush(); + + $io->success('Successfully changed the state of the users!'); + + return self::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Command/User/UserListCommand.php b/src/Command/User/UserListCommand.php index 61d6a6d6..8c3f2e12 100644 --- a/src/Command/User/UserListCommand.php +++ b/src/Command/User/UserListCommand.php @@ -43,7 +43,7 @@ class UserListCommand extends Command $io->title('Users:'); $table = new Table($output); - $table->setHeaders(['ID', 'Username', 'Name', 'Email', 'Group']); + $table->setHeaders(['ID', 'Username', 'Name', 'Email', 'Group', 'Login Disabled']); foreach ($users as $user) { $table->addRow([ @@ -52,6 +52,7 @@ class UserListCommand extends Command $user->getFullName(), $user->getEmail(), $user->getGroup() !== null ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group', + $user->isDisabled() ? 'Yes' : 'No', ]); } diff --git a/src/Command/User/UsersPermissionsCommand.php b/src/Command/User/UsersPermissionsCommand.php new file mode 100644 index 00000000..5bb3f11c --- /dev/null +++ b/src/Command/User/UsersPermissionsCommand.php @@ -0,0 +1,204 @@ +entityManager = $entityManager; + $this->userRepository = $entityManager->getRepository(User::class); + $this->permissionResolver = $permissionResolver; + $this->translator = $translator; + + parent::__construct(self::$defaultName); + } + + protected function configure(): void + { + $this + ->addArgument('user', InputArgument::REQUIRED, 'The username of the user to view') + ->addOption('noInherit', null, InputOption::VALUE_NONE, 'Do not inherit permissions from groups') + ->addOption('edit', '', InputOption::VALUE_NONE, 'Edit the permissions of the user') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $username = $input->getArgument('user'); + $edit_mode = $input->getOption('edit'); + $inherit = !$input->getOption('noInherit') && !$edit_mode; //Show the non inherited perms in edit mode + + //Find user + $io->note('Finding user with username: ' . $username); + $user = $this->userRepository->findByEmailOrName($username); + if ($user === null) { + $io->error('No user found with username: ' . $username); + return Command::FAILURE; + } + + $io->note(sprintf('Found user %s with ID %d', $user->getFullName(true), $user->getId())); + + $edit_mapping = $this->renderPermissionTable($output, $user, $inherit); + + while($edit_mode) { + $index_to_edit = $io->ask('Which permission do you want to edit? Enter the index (e.g. 2-4) to edit, * for all permissions or "q" to quit', 'q'); + if ($index_to_edit === 'q') { + break; + } + + if (!isset($edit_mapping[$index_to_edit]) && $index_to_edit !== '*') { + $io->error('Invalid index'); + continue; + } + + if ($index_to_edit === '*') { + $io->warning('You are about to edit all permissions. This will overwrite all permissions!'); + } else { + [$perm_to_edit, $op_to_edit] = $edit_mapping[$index_to_edit]; + $io->note('Editing permission ' . $perm_to_edit . ' with operation ' . $op_to_edit); + } + + + $new_value_str = $io->ask('Enter the new value for the permission (A = allow, D = disallow, I = inherit)'); + switch (strtolower($new_value_str)) { + case 'a': + case 'allow': + $new_value = true; + break; + case 'd': + case 'disallow': + $new_value = false; + break; + case 'i': + case 'inherit': + $new_value = null; + break; + default: + $io->error('Invalid value'); + continue 2; + } + + if ($index_to_edit === '*') { + $this->permissionResolver->setAllPermissions($user, $new_value); + $io->success('Permission updated successfully'); + $this->entityManager->flush(); + + break; //Show the new table + } + + if (isset($op_to_edit, $perm_to_edit)) { + $this->permissionResolver->setPermission($user, $perm_to_edit, $op_to_edit, $new_value); + } else { + throw new \RuntimeException('Erorr while editing permission'); + } + + //Ensure that all operations are set accordingly + $this->permissionResolver->ensureCorrectSetOperations($user); + $io->success('Permission updated successfully'); + + //Save to DB + $this->entityManager->flush(); + } + + if ($edit_mode) { + $io->note('New permissions:'); + $this->renderPermissionTable($output, $user, true); + } + + return Command::SUCCESS; + } + + protected function renderPermissionTable(OutputInterface $output, User $user, bool $inherit): array + { + //We fill this with index and perm/op combination for later use + $edit_mapping = []; + + $table = new Table($output); + + $perms = $this->permissionResolver->getPermissionStructure()['perms']; + + if ($inherit) { + $table->setHeaderTitle('Inherited Permissions for '.$user->getFullName(true)); + } else { + $table->setHeaderTitle('Non Inherited Permissions for '.$user->getFullName(true)); + } + + $table->setHeaders(['', 'Permission', 'Operation', 'Value']); + + $perm_index = '1'; + + foreach ($perms as $perm_name => $perm_obj) { + $op_index = 1; + foreach ($perm_obj['operations'] as $operation_name => $operation_obj) { + + $index = sprintf('%d-%d', $perm_index, $op_index); + + $table->addRow([ + $index, + $this->translator->trans($perm_obj['label']), //Permission name + $this->translator->trans($operation_obj['label']), //Operation name + $this->getPermissionValue($user, $perm_name, $operation_name, $inherit), + ]); + + //Save index and perm/op combination for editing later + $edit_mapping[$index] = [ + $perm_name, $operation_name, + ]; + + $op_index++; + } + $table->addRow(new TableSeparator()); + + $perm_index++; + } + + $table->render(); + + return $edit_mapping; + } + + protected function getPermissionValue(User $user, string $permission, string $op, bool $inherit = true): string + { + if ($inherit) { + $permission_value = $this->permissionResolver->inherit($user, $permission, $op); + } else { + $permission_value = $this->permissionResolver->dontInherit($user, $permission, $op); + } + + if ($permission_value === true) { + return 'Allow'; + } else if ($permission_value === false) { + return 'Disallow'; + } else if ($permission_value === null && !$inherit) { + return 'Inherit'; + } else if ($permission_value === null && $inherit) { + return 'Disallow (Inherited)'; + } + + return '???'; + } +} diff --git a/src/Controller/AdminPages/BaseAdminController.php b/src/Controller/AdminPages/BaseAdminController.php index f64a8648..cc161b22 100644 --- a/src/Controller/AdminPages/BaseAdminController.php +++ b/src/Controller/AdminPages/BaseAdminController.php @@ -143,7 +143,6 @@ abstract class BaseAdminController extends AbstractController protected function revertElementIfNeeded(AbstractDBElement $entity, ?string $timestamp): ?DateTime { if (null !== $timestamp) { - $this->denyAccessUnlessGranted('@tools.timetravel'); $this->denyAccessUnlessGranted('show_history', $entity); //If the timestamp only contains numbers interpret it as unix timestamp if (ctype_digit($timestamp)) { diff --git a/src/Controller/AttachmentFileController.php b/src/Controller/AttachmentFileController.php index 34501024..bfacb478 100644 --- a/src/Controller/AttachmentFileController.php +++ b/src/Controller/AttachmentFileController.php @@ -131,7 +131,7 @@ class AttachmentFileController extends AbstractController */ public function attachmentsTable(Request $request, DataTableFactory $dataTableFactory, NodesListBuilder $nodesListBuilder) { - $this->denyAccessUnlessGranted('read', new PartAttachment()); + $this->denyAccessUnlessGranted('@attachments.list_attachments'); $formRequest = clone $request; $formRequest->setMethod('GET'); diff --git a/src/Controller/GroupController.php b/src/Controller/GroupController.php index 2b6cca8a..d13454f4 100644 --- a/src/Controller/GroupController.php +++ b/src/Controller/GroupController.php @@ -51,6 +51,7 @@ use App\Form\AdminPages\GroupAdminForm; use App\Services\EntityExporter; use App\Services\EntityImporter; use App\Services\StructuralElementRecursionHelper; +use App\Services\UserSystem\PermissionPresetsHelper; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -73,8 +74,27 @@ class GroupController extends BaseAdminController * @Route("/{id}/edit/{timestamp}", requirements={"id"="\d+"}, name="group_edit") * @Route("/{id}/", requirements={"id"="\d+"}) */ - public function edit(Group $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response + public function edit(Group $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, ?string $timestamp = null): Response { + //Handle permissions presets + if ($request->request->has('permission_preset')) { + $this->denyAccessUnlessGranted('edit_permissions', $entity); + if ($this->isCsrfTokenValid('group'.$entity->getId(), $request->request->get('_token'))) { + $preset = $request->request->get('permission_preset'); + + $permissionPresetsHelper->applyPreset($entity, $preset); + + $em->flush(); + + $this->addFlash('success', 'user.edit.permission_success'); + + //We need to stop the execution here, or our permissions changes will be overwritten by the form values + return $this->redirectToRoute('group_edit', ['id' => $entity->getID()]); + } else { + $this->addFlash('danger', 'csfr_invalid'); + } + } + return $this->_edit($entity, $request, $em, $timestamp); } diff --git a/src/Controller/PartController.php b/src/Controller/PartController.php index da9f245a..55892a47 100644 --- a/src/Controller/PartController.php +++ b/src/Controller/PartController.php @@ -102,7 +102,6 @@ class PartController extends AbstractController $timeTravel_timestamp = null; if (null !== $timestamp) { - $this->denyAccessUnlessGranted('@tools.timetravel'); $this->denyAccessUnlessGranted('show_history', $part); //If the timestamp only contains numbers interpret it as unix timestamp if (ctype_digit($timestamp)) { diff --git a/src/Controller/PartListsController.php b/src/Controller/PartListsController.php index fdd01821..af18aeea 100644 --- a/src/Controller/PartListsController.php +++ b/src/Controller/PartListsController.php @@ -175,6 +175,8 @@ class PartListsController extends AbstractController */ public function showCategory(Category $category, Request $request) { + $this->denyAccessUnlessGranted('@categories.read'); + return $this->showListWithFilter($request, 'Parts/lists/category_list.html.twig', function (PartFilter $filter) use ($category) { @@ -195,6 +197,8 @@ class PartListsController extends AbstractController */ public function showFootprint(Footprint $footprint, Request $request) { + $this->denyAccessUnlessGranted('@footprints.read'); + return $this->showListWithFilter($request, 'Parts/lists/footprint_list.html.twig', function (PartFilter $filter) use ($footprint) { @@ -215,6 +219,8 @@ class PartListsController extends AbstractController */ public function showManufacturer(Manufacturer $manufacturer, Request $request) { + $this->denyAccessUnlessGranted('@manufacturers.read'); + return $this->showListWithFilter($request, 'Parts/lists/manufacturer_list.html.twig', function (PartFilter $filter) use ($manufacturer) { @@ -235,6 +241,8 @@ class PartListsController extends AbstractController */ public function showStorelocation(Storelocation $storelocation, Request $request) { + $this->denyAccessUnlessGranted('@storelocations.read'); + return $this->showListWithFilter($request, 'Parts/lists/store_location_list.html.twig', function (PartFilter $filter) use ($storelocation) { @@ -255,6 +263,8 @@ class PartListsController extends AbstractController */ public function showSupplier(Supplier $supplier, Request $request) { + $this->denyAccessUnlessGranted('@suppliers.read'); + return $this->showListWithFilter($request, 'Parts/lists/supplier_list.html.twig', function (PartFilter $filter) use ($supplier) { diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php index 9c77c442..c2cf0ba8 100644 --- a/src/Controller/SecurityController.php +++ b/src/Controller/SecurityController.php @@ -45,7 +45,7 @@ namespace App\Controller; use App\Entity\UserSystem\User; use App\Events\SecurityEvent; use App\Events\SecurityEvents; -use App\Services\PasswordResetManager; +use App\Services\UserSystem\PasswordResetManager; use Doctrine\ORM\EntityManagerInterface; use Gregwar\CaptchaBundle\Type\CaptchaType; use RuntimeException; diff --git a/src/Controller/SelectAPIController.php b/src/Controller/SelectAPIController.php index b84789f0..594b3166 100644 --- a/src/Controller/SelectAPIController.php +++ b/src/Controller/SelectAPIController.php @@ -33,6 +33,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; /** * @Route("/select_api") + * + * This endpoint is used by the select2 library to dynamically load data (used in the multiselect action helper in parts lists) */ class SelectAPIController extends AbstractController { diff --git a/src/Controller/ToolsController.php b/src/Controller/ToolsController.php index a7a95db6..dd857797 100644 --- a/src/Controller/ToolsController.php +++ b/src/Controller/ToolsController.php @@ -2,6 +2,9 @@ namespace App\Controller; +use App\Services\GitVersionInfo; +use App\Services\Misc\DBInfoHelper; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -20,4 +23,47 @@ class ToolsController extends AbstractController return $this->render('Tools/ReelCalculator/main.html.twig'); } + + /** + * @Route("/server_infos", name="tools_server_infos") + */ + public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHelper): Response + { + $this->denyAccessUnlessGranted('@system.server_infos'); + + return $this->render('Tools/ServerInfos/main.html.twig', [ + //Part-DB section + 'git_branch' => $versionInfo->getGitBranchName(), + 'git_commit' => $versionInfo->getGitCommitHash(), + 'default_locale' => $this->getParameter('partdb.locale'), + 'default_timezone' => $this->getParameter('partdb.timezone'), + 'default_currency' => $this->getParameter('partdb.default_currency'), + 'default_theme' => $this->getParameter('partdb.global_theme'), + 'enabled_locales' => $this->getParameter('partdb.locale_menu'), + 'demo_mode' => $this->getParameter('partdb.demo_mode'), + 'gpdr_compliance' => $this->getParameter('partdb.gpdr_compliance'), + 'use_gravatar' => $this->getParameter('partdb.users.use_gravatar'), + 'email_password_reset' => $this->getParameter('partdb.users.email_pw_reset'), + 'enviroment' => $this->getParameter('kernel.environment'), + 'is_debug' => $this->getParameter('kernel.debug'), + 'email_sender' => $this->getParameter('partdb.mail.sender_email'), + 'email_sender_name' => $this->getParameter('partdb.mail.sender_name'), + 'allow_attachments_downloads' => $this->getParameter('partdb.attachments.allow_downloads'), + 'detailed_error_pages' => $this->getParameter('partdb.error_pages.show_help'), + 'error_page_admin_email' => $this->getParameter('partdb.error_pages.admin_email'), + + //PHP section + 'php_version' => PHP_VERSION, + 'php_uname' => php_uname('a'), + 'php_sapi' => PHP_SAPI, + 'php_extensions' => array_merge(get_loaded_extensions()), + 'php_opcache_enabled' => ini_get('opcache.enable'), + 'php_upload_max_filesize' => ini_get('upload_max_filesize'), + 'php_post_max_size' => ini_get('post_max_size'), + + //DB section + 'db_type' => $DBInfoHelper->getDatabaseType() ?? 'Unknown', + 'db_version' => $DBInfoHelper->getDatabaseVersion() ?? 'Unknown', + ]); + } } diff --git a/src/Controller/TreeController.php b/src/Controller/TreeController.php index 4c72ac8a..500c5c00 100644 --- a/src/Controller/TreeController.php +++ b/src/Controller/TreeController.php @@ -84,7 +84,11 @@ class TreeController extends AbstractController */ public function categoryTree(?Category $category = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Category::class, $category, 'list_parts_root'); + if ($this->isGranted('@parts.read') && $this->isGranted('@categories.read')) { + $tree = $this->treeGenerator->getTreeView(Category::class, $category, 'list_parts_root'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } @@ -95,8 +99,11 @@ class TreeController extends AbstractController */ public function footprintTree(?Footprint $footprint = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint, 'list_parts_root'); - + if ($this->isGranted('@parts.read') && $this->isGranted('@footprints.read')) { + $tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint, 'list_parts_root'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } @@ -106,7 +113,11 @@ class TreeController extends AbstractController */ public function locationTree(?Storelocation $location = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Storelocation::class, $location, 'list_parts_root'); + if ($this->isGranted('@parts.read') && $this->isGranted('@storelocations.read')) { + $tree = $this->treeGenerator->getTreeView(Storelocation::class, $location, 'list_parts_root'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } @@ -117,7 +128,11 @@ class TreeController extends AbstractController */ public function manufacturerTree(?Manufacturer $manufacturer = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer, 'list_parts_root'); + if ($this->isGranted('@parts.read') && $this->isGranted('@manufacturers.read')) { + $tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer, 'list_parts_root'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } @@ -128,7 +143,11 @@ class TreeController extends AbstractController */ public function supplierTree(?Supplier $supplier = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier, 'list_parts_root'); + if ($this->isGranted('@parts.read') && $this->isGranted('@suppliers.read')) { + $tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier, 'list_parts_root'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } @@ -139,7 +158,11 @@ class TreeController extends AbstractController */ public function deviceTree(?Device $device = null): JsonResponse { - $tree = $this->treeGenerator->getTreeView(Device::class, $device, 'devices'); + if ($this->isGranted('@devices.read')) { + $tree = $this->treeGenerator->getTreeView(Device::class, $device, 'devices'); + } else { + return new JsonResponse("Access denied", 403); + } return new JsonResponse($tree); } diff --git a/src/Controller/TypeaheadController.php b/src/Controller/TypeaheadController.php index 92571df9..c0ace8f2 100644 --- a/src/Controller/TypeaheadController.php +++ b/src/Controller/TypeaheadController.php @@ -156,6 +156,11 @@ class TypeaheadController extends AbstractController public function parameters(string $type, EntityManagerInterface $entityManager, string $query = ""): JsonResponse { $class = $this->typeToParameterClass($type); + + $test_obj = new $class(); + //Ensure user has the correct permissions + $this->denyAccessUnlessGranted('read', $test_obj); + /** @var ParameterRepository $repository */ $repository = $entityManager->getRepository($class); @@ -169,6 +174,8 @@ class TypeaheadController extends AbstractController */ public function tags(string $query, TagFinder $finder): JsonResponse { + $this->denyAccessUnlessGranted('@parts.read'); + $array = $finder->searchTags($query); $normalizers = [ diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index a8a2b860..1b53255b 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -54,6 +54,7 @@ use App\Form\UserAdminForm; use App\Services\EntityExporter; use App\Services\EntityImporter; use App\Services\StructuralElementRecursionHelper; +use App\Services\UserSystem\PermissionPresetsHelper; use Doctrine\ORM\EntityManagerInterface; use Exception; use InvalidArgumentException; @@ -101,7 +102,7 @@ class UserController extends AdminPages\BaseAdminController * * @throws Exception */ - public function edit(User $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response + public function edit(User $entity, Request $request, EntityManagerInterface $em, PermissionPresetsHelper $permissionPresetsHelper, ?string $timestamp = null): Response { //Handle 2FA disabling @@ -132,6 +133,25 @@ class UserController extends AdminPages\BaseAdminController } } + //Handle permissions presets + if ($request->request->has('permission_preset')) { + $this->denyAccessUnlessGranted('edit_permissions', $entity); + if ($this->isCsrfTokenValid('reset_2fa'.$entity->getId(), $request->request->get('_token'))) { + $preset = $request->request->get('permission_preset'); + + $permissionPresetsHelper->applyPreset($entity, $preset); + + $em->flush(); + + $this->addFlash('success', 'user.edit.permission_success'); + + //We need to stop the execution here, or our permissions changes will be overwritten by the form values + return $this->redirectToRoute('user_edit', ['id' => $entity->getID()]); + } else { + $this->addFlash('danger', 'csfr_invalid'); + } + } + return $this->_edit($entity, $request, $em, $timestamp); } diff --git a/src/Controller/UserSettingsController.php b/src/Controller/UserSettingsController.php index 27d80c66..b8163ed8 100644 --- a/src/Controller/UserSettingsController.php +++ b/src/Controller/UserSettingsController.php @@ -49,7 +49,7 @@ use App\Events\SecurityEvent; use App\Events\SecurityEvents; use App\Form\TFAGoogleSettingsType; use App\Form\UserSettingsType; -use App\Services\TFA\BackupCodeManager; +use App\Services\UserSystem\TFA\BackupCodeManager; use Doctrine\ORM\EntityManagerInterface; use RuntimeException; use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticator; diff --git a/src/Controller/WebauthnKeyRegistrationController.php b/src/Controller/WebauthnKeyRegistrationController.php index 945fc2f0..f778d9ce 100644 --- a/src/Controller/WebauthnKeyRegistrationController.php +++ b/src/Controller/WebauthnKeyRegistrationController.php @@ -18,6 +18,8 @@ class WebauthnKeyRegistrationController extends AbstractController */ public function register(Request $request, TFAWebauthnRegistrationHelper $registrationHelper, EntityManagerInterface $em) { + //When user change its settings, he should be logged in fully. + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); //If form was submitted, check the auth response if ($request->getMethod() === 'POST') { @@ -51,7 +53,7 @@ class WebauthnKeyRegistrationController extends AbstractController return $this->render( - 'Security/Webauthn/webauthn_register.html.twig', + 'security/Webauthn/webauthn_register.html.twig', [ 'registrationRequest' => $registrationHelper->generateRegistrationRequestAsJSON(), ] diff --git a/src/DataFixtures/GroupFixtures.php b/src/DataFixtures/GroupFixtures.php index c17bccdf..a7c872f0 100644 --- a/src/DataFixtures/GroupFixtures.php +++ b/src/DataFixtures/GroupFixtures.php @@ -43,6 +43,8 @@ declare(strict_types=1); namespace App\DataFixtures; use App\Entity\UserSystem\Group; +use App\Services\UserSystem\PermissionManager; +use App\Services\UserSystem\PermissionPresetsHelper; use Doctrine\Bundle\FixturesBundle\Fixture; use Doctrine\Persistence\ObjectManager; @@ -52,138 +54,45 @@ class GroupFixtures extends Fixture public const USERS = 'group-users'; public const READONLY = 'group-readonly'; + + private PermissionPresetsHelper $permission_presets; + private PermissionManager $permissionManager; + + public function __construct(PermissionPresetsHelper $permissionPresetsHelper, PermissionManager $permissionManager) + { + $this->permission_presets = $permissionPresetsHelper; + $this->permissionManager = $permissionManager; + } + public function load(ObjectManager $manager): void { $admins = new Group(); $admins->setName('admins'); - //Perm values taken from Version 1 - $admins->getPermissions()->setRawPermissionValues([ - 'system' => 21, - 'groups' => 1365, - 'users' => 87381, - 'self' => 85, - 'config' => 85, - 'database' => 21, - 'parts' => 1431655765, - 'parts_name' => 5, - 'parts_description' => 5, - 'parts_footprint' => 5, - 'parts_manufacturer' => 5, - 'parts_comment' => 5, - 'parts_order' => 5, - 'parts_orderdetails' => 341, - 'parts_prices' => 341, - 'parts_attachments' => 341, - 'devices' => 5461, - 'devices_parts' => 325, - 'storelocations' => 5461, - 'footprints' => 5461, - 'categories' => 5461, - 'suppliers' => 5461, - 'manufacturers' => 5461, - 'attachment_types' => 1365, - 'tools' => 349525, - 'labels' => 87381, - 'parts_category' => 5, - 'parts_minamount' => 5, - 'parts_lots' => 85, - 'parts_tags' => 5, - 'parts_unit' => 5, - 'parts_mass' => 5, - 'parts_status' => 5, - 'parts_mpn' => 5, - 'currencies' => 5461, - 'measurement_units' => 5461, - ]); + //Set permissions using preset + $this->permission_presets->applyPreset($admins, PermissionPresetsHelper::PRESET_ALL_ALLOW); + $this->addDevicesPermissions($admins); $this->setReference(self::ADMINS, $admins); $manager->persist($admins); $readonly = new Group(); $readonly->setName('readonly'); - $readonly->getPermissions()->setRawPermissionValues([ - 'system' => 2, - 'groups' => 2730, - 'users' => 43690, - 'self' => 25, - 'config' => 170, - 'database' => 42, - 'parts' => 2778027689, - 'parts_name' => 9, - 'parts_description' => 9, - 'parts_footprint' => 9, - 'parts_manufacturer' => 9, - 'parts_comment' => 9, - 'parts_order' => 9, - 'parts_orderdetails' => 681, - 'parts_prices' => 681, - 'parts_attachments' => 681, - 'devices' => 1705, - 'devices_parts' => 649, - 'storelocations' => 1705, - 'footprints' => 1705, - 'categories' => 1705, - 'suppliers' => 1705, - 'manufacturers' => 1705, - 'attachment_types' => 681, - 'tools' => 87382, - 'labels' => 173737, - 'parts_category' => 9, - 'parts_minamount' => 9, - 'parts_lots' => 169, - 'parts_tags' => 9, - 'parts_unit' => 9, - 'parts_mass' => 9, - 'parts_status' => 9, - 'parts_mpn' => 9, - 'currencies' => 9897, - 'measurement_units' => 9897, - ]); + $this->permission_presets->applyPreset($readonly, PermissionPresetsHelper::PRESET_READ_ONLY); $this->setReference(self::READONLY, $readonly); $manager->persist($readonly); $users = new Group(); $users->setName('users'); - $users->getPermissions()->setRawPermissionValues([ - 'system' => 42, - 'groups' => 2730, - 'users' => 43690, - 'self' => 89, - 'config' => 105, - 'database' => 41, - 'parts' => 1431655765, - 'parts_name' => 5, - 'parts_description' => 5, - 'parts_footprint' => 5, - 'parts_manufacturer' => 5, - 'parts_comment' => 5, - 'parts_order' => 5, - 'parts_orderdetails' => 341, - 'parts_prices' => 341, - 'parts_attachments' => 341, - 'devices' => 5461, - 'devices_parts' => 325, - 'storelocations' => 5461, - 'footprints' => 5461, - 'categories' => 5461, - 'suppliers' => 5461, - 'manufacturers' => 5461, - 'attachment_types' => 1365, - 'tools' => 87381, - 'labels' => 91477, - 'parts_category' => 5, - 'parts_minamount' => 5, - 'parts_lots' => 85, - 'parts_tags' => 5, - 'parts_unit' => 5, - 'parts_mass' => 5, - 'parts_status' => 5, - 'parts_mpn' => 5, - 'currencies' => 5461, - 'measurement_units' => 5461, - ]); + $this->permission_presets->applyPreset($users, PermissionPresetsHelper::PRESET_EDITOR); + $this->addDevicesPermissions($users); $this->setReference(self::USERS, $users); $manager->persist($users); $manager->flush(); } + + private function addDevicesPermissions(Group $group): void + { + $this->permissionManager->setAllOperationsOfPermission($group, 'devices', true); + } + } diff --git a/src/DataTables/LogDataTable.php b/src/DataTables/LogDataTable.php index 8842ac3a..20439c4d 100644 --- a/src/DataTables/LogDataTable.php +++ b/src/DataTables/LogDataTable.php @@ -260,9 +260,7 @@ class LogDataTable implements DataTableTypeInterface return null; }, 'disabled' => function ($value, AbstractLogEntry $context) { - return - !$this->security->isGranted('@tools.timetravel') - || !$this->security->isGranted('show_history', $context->getTargetClass()); + return !$this->security->isGranted('show_history', $context->getTargetClass()); }, ]); diff --git a/src/DataTables/PartsDataTable.php b/src/DataTables/PartsDataTable.php index 16f530dd..eb9798b6 100644 --- a/src/DataTables/PartsDataTable.php +++ b/src/DataTables/PartsDataTable.php @@ -163,20 +163,29 @@ final class PartsDataTable implements DataTableTypeInterface ]) ->add('description', MarkdownColumn::class, [ 'label' => $this->translator->trans('part.table.description'), - ]) - ->add('category', EntityColumn::class, [ + ]); + + if ($this->security->isGranted('@categories.read')) { + $dataTable->add('category', EntityColumn::class, [ 'label' => $this->translator->trans('part.table.category'), 'property' => 'category', - ]) - ->add('footprint', EntityColumn::class, [ + ]); + } + + if ($this->security->isGranted('@footprints.read')) { + $dataTable->add('footprint', EntityColumn::class, [ 'property' => 'footprint', 'label' => $this->translator->trans('part.table.footprint'), - ]) - ->add('manufacturer', EntityColumn::class, [ + ]); + } + if ($this->security->isGranted('@manufacturers.read')) { + $dataTable->add('manufacturer', EntityColumn::class, [ 'property' => 'manufacturer', 'label' => $this->translator->trans('part.table.manufacturer'), - ]) - ->add('storelocation', TextColumn::class, [ + ]); + } + if ($this->security->isGranted('@storelocations.read')) { + $dataTable->add('storelocation', TextColumn::class, [ 'label' => $this->translator->trans('part.table.storeLocations'), 'render' => function ($value, Part $context) { $tmp = []; @@ -194,32 +203,38 @@ final class PartsDataTable implements DataTableTypeInterface return implode('
', $tmp); }, - ]) - ->add('amount', TextColumn::class, [ - 'label' => $this->translator->trans('part.table.amount'), - 'render' => function ($value, Part $context) { - $amount = $context->getAmountSum(); + ]); + } - return $this->amountFormatter->format($amount, $context->getPartUnit()); - }, - 'orderField' => 'amountSum' - ]) + $dataTable->add('amount', TextColumn::class, [ + 'label' => $this->translator->trans('part.table.amount'), + 'render' => function ($value, Part $context) { + $amount = $context->getAmountSum(); + + return $this->amountFormatter->format($amount, $context->getPartUnit()); + }, + 'orderField' => 'amountSum' + ]) ->add('minamount', TextColumn::class, [ 'label' => $this->translator->trans('part.table.minamount'), 'visible' => false, 'render' => function ($value, Part $context) { return $this->amountFormatter->format($value, $context->getPartUnit()); }, - ]) - ->add('partUnit', TextColumn::class, [ + ]); + + if ($this->security->isGranted('@footprints.read')) { + $dataTable->add('partUnit', TextColumn::class, [ 'field' => 'partUnit.name', 'label' => $this->translator->trans('part.table.partUnit'), 'visible' => false, - ]) - ->add('addedDate', LocaleDateTimeColumn::class, [ - 'label' => $this->translator->trans('part.table.addedDate'), - 'visible' => false, - ]) + ]); + } + + $dataTable->add('addedDate', LocaleDateTimeColumn::class, [ + 'label' => $this->translator->trans('part.table.addedDate'), + 'visible' => false, + ]) ->add('lastModified', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.lastModified'), 'visible' => false, diff --git a/src/Entity/Base/AbstractDBElement.php b/src/Entity/Base/AbstractDBElement.php index b3cadb25..000e912d 100644 --- a/src/Entity/Base/AbstractDBElement.php +++ b/src/Entity/Base/AbstractDBElement.php @@ -37,8 +37,6 @@ use Symfony\Component\Serializer\Annotation\Groups; * * @ORM\MappedSuperclass(repositoryClass="App\Repository\DBElementRepository") * - * @ORM\EntityListeners({"App\Security\EntityListeners\ElementPermissionListener"}) - * * @DiscriminatorMap(typeProperty="type", mapping={ * "attachment_type" = "App\Entity\AttachmentType", * "attachment" = "App\Entity\Attachment", diff --git a/src/Entity/Base/AbstractStructuralDBElement.php b/src/Entity/Base/AbstractStructuralDBElement.php index f5c99b1b..b4617bad 100644 --- a/src/Entity/Base/AbstractStructuralDBElement.php +++ b/src/Entity/Base/AbstractStructuralDBElement.php @@ -45,7 +45,7 @@ use Symfony\Component\Serializer\Annotation\Groups; * * @ORM\MappedSuperclass(repositoryClass="App\Repository\StructuralDBElementRepository") * - * @ORM\EntityListeners({"App\Security\EntityListeners\ElementPermissionListener", "App\EntityListeners\TreeCacheInvalidationListener"}) + * @ORM\EntityListeners({"App\EntityListeners\TreeCacheInvalidationListener"}) * * @UniqueEntity(fields={"name", "parent"}, ignoreNull=false, message="structural.entity.unique_name") */ diff --git a/src/Entity/Parts/Part.php b/src/Entity/Parts/Part.php index 00514f64..87c79877 100644 --- a/src/Entity/Parts/Part.php +++ b/src/Entity/Parts/Part.php @@ -61,7 +61,6 @@ use App\Entity\Parts\PartTraits\BasicPropertyTrait; use App\Entity\Parts\PartTraits\InstockTrait; use App\Entity\Parts\PartTraits\ManufacturerTrait; use App\Entity\Parts\PartTraits\OrderTrait; -use App\Security\Annotations\ColumnSecurity; use DateTime; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; @@ -103,7 +102,6 @@ class Part extends AttachmentContainingDBElement protected $parameters; /** - * @ColumnSecurity(type="datetime") * @ORM\Column(type="datetime", name="datetime_added", options={"default"="CURRENT_TIMESTAMP"}) */ protected ?DateTime $addedDate = null; @@ -116,14 +114,12 @@ class Part extends AttachmentContainingDBElement /** * @var string The name of this part * @ORM\Column(type="string") - * @ColumnSecurity(prefix="name") */ protected string $name = ''; /** * @var Collection * @ORM\OneToMany(targetEntity="App\Entity\Attachments\PartAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true) - * @ColumnSecurity(type="collection", prefix="attachments") * @ORM\OrderBy({"name" = "ASC"}) * @Assert\Valid() */ @@ -131,7 +127,6 @@ class Part extends AttachmentContainingDBElement /** * @var DateTime the date when this element was modified the last time - * @ColumnSecurity(type="datetime") * @ORM\Column(type="datetime", name="last_modified", options={"default"="CURRENT_TIMESTAMP"}) */ protected ?DateTime $lastModified = null; diff --git a/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php index 2413490c..5113225e 100644 --- a/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php +++ b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php @@ -43,7 +43,6 @@ declare(strict_types=1); namespace App\Entity\Parts\PartTraits; use App\Entity\Parts\Part; -use App\Security\Annotations\ColumnSecurity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -55,21 +54,18 @@ trait AdvancedPropertyTrait /** * @var bool Determines if this part entry needs review (for example, because it is work in progress) * @ORM\Column(type="boolean") - * @ColumnSecurity(type="boolean") */ protected bool $needs_review = false; /** * @var string a comma separated list of tags, associated with the part * @ORM\Column(type="text") - * @ColumnSecurity(type="string", prefix="tags", placeholder="") */ protected string $tags = ''; /** * @var float|null how much a single part unit weighs in grams * @ORM\Column(type="float", nullable=true) - * @ColumnSecurity(type="float", placeholder=null) * @Assert\PositiveOrZero() */ protected ?float $mass = null; diff --git a/src/Entity/Parts/PartTraits/BasicPropertyTrait.php b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php index f43b6f7a..0e2f1f08 100644 --- a/src/Entity/Parts/PartTraits/BasicPropertyTrait.php +++ b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php @@ -44,7 +44,6 @@ namespace App\Entity\Parts\PartTraits; use App\Entity\Parts\Category; use App\Entity\Parts\Footprint; -use App\Security\Annotations\ColumnSecurity; use App\Validator\Constraints\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -54,14 +53,12 @@ trait BasicPropertyTrait /** * @var string A text describing what this part does * @ORM\Column(type="text") - * @ColumnSecurity(prefix="description") */ protected string $description = ''; /** * @var string A comment/note related to this part * @ORM\Column(type="text") - * @ColumnSecurity(prefix="comment") */ protected string $comment = ''; @@ -74,7 +71,6 @@ trait BasicPropertyTrait /** * @var bool true, if the part is marked as favorite * @ORM\Column(type="boolean") - * @ColumnSecurity(type="boolean") */ protected bool $favorite = false; @@ -83,7 +79,6 @@ trait BasicPropertyTrait * Every part must have a category. * @ORM\ManyToOne(targetEntity="Category") * @ORM\JoinColumn(name="id_category", referencedColumnName="id", nullable=false) - * @ColumnSecurity(prefix="category", type="App\Entity\Parts\Category") * @Selectable() * @Assert\NotNull(message="validator.select_valid_category") */ @@ -93,7 +88,6 @@ trait BasicPropertyTrait * @var Footprint|null The footprint of this part (e.g. DIP8) * @ORM\ManyToOne(targetEntity="Footprint") * @ORM\JoinColumn(name="id_footprint", referencedColumnName="id") - * @ColumnSecurity(prefix="footprint", type="App\Entity\Parts\Footprint") * @Selectable() */ protected ?Footprint $footprint = null; diff --git a/src/Entity/Parts/PartTraits/InstockTrait.php b/src/Entity/Parts/PartTraits/InstockTrait.php index deca8424..f2d80559 100644 --- a/src/Entity/Parts/PartTraits/InstockTrait.php +++ b/src/Entity/Parts/PartTraits/InstockTrait.php @@ -44,7 +44,6 @@ namespace App\Entity\Parts\PartTraits; use App\Entity\Parts\MeasurementUnit; use App\Entity\Parts\PartLot; -use App\Security\Annotations\ColumnSecurity; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -58,7 +57,6 @@ trait InstockTrait * @var Collection|PartLot[] A list of part lots where this part is stored * @ORM\OneToMany(targetEntity="PartLot", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true) * @Assert\Valid() - * @ColumnSecurity(type="collection", prefix="lots") * @ORM\OrderBy({"amount" = "DESC"}) */ protected $partLots; @@ -68,7 +66,6 @@ trait InstockTrait * Given in the partUnit. * @ORM\Column(type="float") * @Assert\PositiveOrZero() - * @ColumnSecurity(prefix="minamount", type="integer") */ protected float $minamount = 0; @@ -76,7 +73,6 @@ trait InstockTrait * @var ?MeasurementUnit the unit in which the part's amount is measured * @ORM\ManyToOne(targetEntity="MeasurementUnit") * @ORM\JoinColumn(name="id_part_unit", referencedColumnName="id", nullable=true) - * @ColumnSecurity(type="object", prefix="unit") */ protected ?MeasurementUnit $partUnit = null; diff --git a/src/Entity/Parts/PartTraits/ManufacturerTrait.php b/src/Entity/Parts/PartTraits/ManufacturerTrait.php index 57b94d7d..c6f788c8 100644 --- a/src/Entity/Parts/PartTraits/ManufacturerTrait.php +++ b/src/Entity/Parts/PartTraits/ManufacturerTrait.php @@ -44,7 +44,6 @@ namespace App\Entity\Parts\PartTraits; use App\Entity\Parts\Manufacturer; use App\Entity\Parts\Part; -use App\Security\Annotations\ColumnSecurity; use App\Validator\Constraints\Selectable; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -58,7 +57,6 @@ trait ManufacturerTrait * @var Manufacturer|null The manufacturer of this part * @ORM\ManyToOne(targetEntity="Manufacturer") * @ORM\JoinColumn(name="id_manufacturer", referencedColumnName="id") - * @ColumnSecurity(prefix="manufacturer", type="App\Entity\Parts\Manufacturer") * @Selectable() */ protected ?Manufacturer $manufacturer = null; @@ -67,14 +65,12 @@ trait ManufacturerTrait * @var string the url to the part on the manufacturer's homepage * @ORM\Column(type="string") * @Assert\Url() - * @ColumnSecurity(prefix="mpn", type="string", placeholder="") */ protected string $manufacturer_product_url = ''; /** * @var string The product number used by the manufacturer. If this is set to "", the name field is used. * @ORM\Column(type="string") - * @ColumnSecurity(prefix="mpn", type="string", placeholder="") */ protected string $manufacturer_product_number = ''; @@ -82,7 +78,6 @@ trait ManufacturerTrait * @var string The production status of this part. Can be one of the specified ones. * @ORM\Column(type="string", length=255, nullable=true) * @Assert\Choice({"announced", "active", "nrfnd", "eol", "discontinued", ""}) - * @ColumnSecurity(type="string", prefix="status", placeholder="") */ protected ?string $manufacturing_status = ''; diff --git a/src/Entity/Parts/PartTraits/OrderTrait.php b/src/Entity/Parts/PartTraits/OrderTrait.php index 12bcb166..bba16a53 100644 --- a/src/Entity/Parts/PartTraits/OrderTrait.php +++ b/src/Entity/Parts/PartTraits/OrderTrait.php @@ -43,7 +43,6 @@ declare(strict_types=1); namespace App\Entity\Parts\PartTraits; use App\Entity\PriceInformations\Orderdetail; -use App\Security\Annotations\ColumnSecurity; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Validator\Constraints as Assert; use function count; @@ -59,7 +58,6 @@ trait OrderTrait * @var Orderdetail[]|Collection the details about how and where you can order this part * @ORM\OneToMany(targetEntity="App\Entity\PriceInformations\Orderdetail", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true) * @Assert\Valid() - * @ColumnSecurity(prefix="orderdetails", type="collection") * @ORM\OrderBy({"supplierpartnr" = "ASC"}) */ protected $orderdetails; @@ -67,14 +65,12 @@ trait OrderTrait /** * @var int * @ORM\Column(type="integer") - * @ColumnSecurity(prefix="order", type="integer") */ protected int $order_quantity = 0; /** * @var bool * @ORM\Column(type="boolean") - * @ColumnSecurity(prefix="order", type="boolean") */ protected bool $manual_order = false; @@ -82,8 +78,6 @@ trait OrderTrait * @var Orderdetail * @ORM\OneToOne(targetEntity="App\Entity\PriceInformations\Orderdetail") * @ORM\JoinColumn(name="order_orderdetails_id", referencedColumnName="id") - * - * @ColumnSecurity(prefix="order", type="object") */ protected ?Orderdetail $order_orderdetail = null; diff --git a/src/Entity/UserSystem/Group.php b/src/Entity/UserSystem/Group.php index 94bdb8e1..bb651a11 100644 --- a/src/Entity/UserSystem/Group.php +++ b/src/Entity/UserSystem/Group.php @@ -95,11 +95,12 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa */ protected $attachments; - /** @var PermissionsEmbed - * @ORM\Embedded(class="PermissionsEmbed", columnPrefix="perms_") + /** + * @var PermissionData * @ValidPermission() + * @ORM\Embedded(class="PermissionData", columnPrefix="permissions_") */ - protected $permissions; + protected PermissionData $permissions; /** @var Collection * @ORM\OneToMany(targetEntity="App\Entity\Parameters\GroupParameter", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=true) @@ -111,7 +112,7 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa public function __construct() { parent::__construct(); - $this->permissions = new PermissionsEmbed(); + $this->permissions = new PermissionData(); $this->users = new ArrayCollection(); } @@ -137,7 +138,7 @@ class Group extends AbstractStructuralDBElement implements HasPermissionsInterfa return $this; } - public function getPermissions(): PermissionsEmbed + public function getPermissions(): PermissionData { return $this->permissions; } diff --git a/src/Entity/UserSystem/PermissionData.php b/src/Entity/UserSystem/PermissionData.php new file mode 100644 index 00000000..e059de34 --- /dev/null +++ b/src/Entity/UserSystem/PermissionData.php @@ -0,0 +1,140 @@ + [ + * operation => value, + * ] + * @ORM\Column(type="json", name="data", options={"default": "[]"}) + */ + protected ?array $data = []; + + /** + * Creates a new Permission Data Instance using the given data. + * By default, a empty array is used, meaning + */ + public function __construct(array $data = []) + { + $this->data = $data; + } + + /** + * Check if a permission value is set for the given permission and operation (meaning there value is not inherit). + * @param string $permission + * @param string $operation + * @return bool True if the permission value is set, false otherwise + */ + public function isPermissionSet(string $permission, string $operation): bool + { + return isset($this->data[$permission][$operation]); + } + + /** + * Returns the permission value for the given permission and operation. + * @param string $permission + * @param string $operation + * @return bool|null True means allow, false means disallow, null means inherit + */ + public function getPermissionValue(string $permission, string $operation): ?bool + { + if ($this->isPermissionSet($permission, $operation)) { + return $this->data[$permission][$operation]; + } + + //If the value is not set explicitly, return null (meaning inherit) + return null; + } + + /** + * Sets the permission value for the given permission and operation. + * @param string $permission + * @param string $operation + * @param bool|null $value + * @return $this + */ + public function setPermissionValue(string $permission, string $operation, ?bool $value): self + { + if ($value === null) { + //If the value is null, unset the permission value (meaning implicit inherit) + unset($this->data[$permission][$operation]); + } else { + //Otherwise, set the pemission value + if(!isset($this->data[$permission])) { + $this->data[$permission] = []; + } + $this->data[$permission][$operation] = $value; + } + + return $this; + } + + /** + * Resets the saved permissions and set all operations to inherit (which means they are not defined). + * @return $this + */ + public function resetPermissions(): self + { + $this->data = []; + return $this; + } + + /** + * Creates a new Permission Data Instance using the given JSON encoded data + * @param string $json + * @return static + * @throws \JsonException + */ + public static function fromJSON(string $json): self + { + $data = json_decode($json, true, 512, JSON_THROW_ON_ERROR); + return new self($data); + } + + public function __clone() + { + $this->data = $this->data; + } + + /** + * Returns an JSON encodable representation of this object. + * @return array|mixed + */ + public function jsonSerialize() + { + $ret = []; + + //Filter out all empty or null values + foreach ($this->data as $permission => $operations) { + $ret[$permission] = array_filter($operations, function ($value) { + return $value !== null; + }); + + //If the permission has no operations, unset it + if (empty($ret[$permission])) { + unset($ret[$permission]); + } + } + + return $ret; + } +} \ No newline at end of file diff --git a/src/Entity/UserSystem/PermissionsEmbed.php b/src/Entity/UserSystem/PermissionsEmbed.php deleted file mode 100644 index 4552083d..00000000 --- a/src/Entity/UserSystem/PermissionsEmbed.php +++ /dev/null @@ -1,523 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Entity\UserSystem; - -use Doctrine\ORM\Mapping as ORM; -use InvalidArgumentException; -use Webmozart\Assert\Assert; - -/** - * This entity represents the permission fields a user or group can have. - * - * @ORM\Embeddable() - */ -class PermissionsEmbed -{ - /** - * Permission values. - */ - public const INHERIT = 0b00; - public const ALLOW = 0b01; - public const DISALLOW = 0b10; - - /** - * Permission strings. - */ - public const STORELOCATIONS = 'storelocations'; - public const FOOTRPINTS = 'footprints'; - public const CATEGORIES = 'categories'; - public const SUPPLIERS = 'suppliers'; - public const MANUFACTURERS = 'manufacturers'; - public const DEVICES = 'devices'; - public const ATTACHMENT_TYPES = 'attachment_types'; - public const MEASUREMENT_UNITS = 'measurement_units'; - public const CURRENCIES = 'currencies'; - public const TOOLS = 'tools'; - public const PARTS = 'parts'; - public const PARTS_NAME = 'parts_name'; - public const PARTS_DESCRIPTION = 'parts_description'; - public const PARTS_MINAMOUNT = 'parts_minamount'; - public const PARTS_FOOTPRINT = 'parts_footprint'; - public const PARTS_MPN = 'parts_mpn'; - public const PARTS_STATUS = 'parts_status'; - public const PARTS_TAGS = 'parts_tags'; - public const PARTS_UNIT = 'parts_unit'; - public const PARTS_MASS = 'parts_mass'; - public const PARTS_LOTS = 'parts_lots'; - public const PARTS_COMMENT = 'parts_comment'; - public const PARTS_MANUFACTURER = 'parts_manufacturer'; - public const PARTS_ORDERDETAILS = 'parts_orderdetails'; - public const PARTS_PRICES = 'parts_prices'; - public const PARTS_ATTACHMENTS = 'parts_attachments'; - public const PARTS_ORDER = 'parts_order'; - public const GROUPS = 'groups'; - public const USERS = 'users'; - public const DATABASE = 'database'; - public const CONFIG = 'config'; - public const SYSTEM = 'system'; - public const DEVICE_PARTS = 'devices_parts'; - public const SELF = 'self'; - public const LABELS = 'labels'; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $system = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $groups = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $users = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $self = 0; - - /** - * @var int - * @ORM\Column(type="integer", name="system_config") - */ - protected $config = 0; - - /** - * @var int - * @ORM\Column(type="integer", name="system_database") - */ - protected $database = 0; - - /** - * @var int - * @ORM\Column(type="bigint") - */ - protected $parts = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_name = 0; - - /** @var int - * @ORM\Column(type="smallint") - */ - protected $parts_category = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_description = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_minamount = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_footprint = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_lots = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_tags = 0; - - /** @var int - * @ORM\Column(type="smallint") - */ - protected $parts_unit = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_mass = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_manufacturer = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_status = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_mpn = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_comment = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_order = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_orderdetails = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_prices = 0; - - /** - * @var int - * @ORM\Column(type="smallint") - */ - protected $parts_parameters = 0; - - /** - * @var int - * @ORM\Column(type="smallint", name="parts_attachements") - */ - protected $parts_attachments = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $devices = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $devices_parts = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $storelocations = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $footprints = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $categories = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $suppliers = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $manufacturers = 0; - - /** - * @var int - * @ORM\Column(type="integer", name="attachement_types") - */ - protected $attachment_types = 0; - - /** @var int - * @ORM\Column(type="integer") - */ - protected $currencies = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $measurement_units = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $tools = 0; - - /** - * @var int - * @ORM\Column(type="integer") - */ - protected $labels = 0; - - /** - * Checks whether a permission with the given name is valid for this object. - * - * @param string $permission_name the name of the permission which should be checked for - * - * @return bool true if the permission is existing on this object - */ - public function isValidPermissionName(string $permission_name): bool - { - return isset($this->{$permission_name}); - } - - /** - * Returns the bit pair value of the given permission. - * - * @param string $permission_name the name of the permission, for which the bit pair should be returned - * @param int $bit_n the (lower) bit number of the bit pair, which should be read - * - * @return int The value of the bit pair. Compare to the INHERIT, ALLOW, and DISALLOW consts in this class. - */ - public function getBitValue(string $permission_name, int $bit_n): int - { - if (!$this->isValidPermissionName($permission_name)) { - throw new InvalidArgumentException(sprintf('No permission with the name "%s" is existing!', $permission_name)); - } - - $perm_int = (int) $this->{$permission_name}; - - return static::readBitPair($perm_int, $bit_n); - } - - /** - * Returns the value of the operation for the given permission. - * - * @param string $permission_name the name of the permission, for which the operation should be returned - * @param int $bit_n the (lower) bit number of the bit pair for the operation - * - * @return bool|null The value of the operation. True, if the given operation is allowed, false if disallowed - * and null if it should inherit from parent. - */ - public function getPermissionValue(string $permission_name, int $bit_n): ?bool - { - $value = $this->getBitValue($permission_name, $bit_n); - if (self::ALLOW === $value) { - return true; - } - - if (self::DISALLOW === $value) { - return false; - } - - return null; - } - - /** - * Sets the value of the given permission and operation. - * - * @param string $permission_name the name of the permission, for which the bit pair should be written - * @param int $bit_n the (lower) bit number of the bit pair, which should be written - * @param bool|null $new_value the new value for the operation: - * True, if the given operation is allowed, false if disallowed - * and null if it should inherit from parent - * - * @return PermissionsEmbed the instance itself - */ - public function setPermissionValue(string $permission_name, int $bit_n, ?bool $new_value): self - { - //Determine which bit value the given value is. - if (true === $new_value) { - $bit_value = static::ALLOW; - } elseif (false === $new_value) { - $bit_value = static::DISALLOW; - } else { - $bit_value = static::INHERIT; - } - - $this->setBitValue($permission_name, $bit_n, $bit_value); - - return $this; - } - - /** - * Sets the bit value of the given permission and operation. - * - * @param string $permission_name the name of the permission, for which the bit pair should be written - * @param int $bit_n the (lower) bit number of the bit pair, which should be written - * @param int $new_value the new (bit) value of the bit pair, which should be written - * - * @return PermissionsEmbed the instance itself - */ - public function setBitValue(string $permission_name, int $bit_n, int $new_value): self - { - if (!$this->isValidPermissionName($permission_name)) { - throw new InvalidArgumentException('No permission with the given name is existing!'); - } - - $this->{$permission_name} = static::writeBitPair((int) $this->{$permission_name}, $bit_n, $new_value); - - return $this; - } - - /** - * Returns the given permission as raw int (all bit at once). - * - * @param string $permission_name The name of the permission, which should be retrieved. - * If this is not existing an exception is thrown. - * - * @return int the raw permission value - */ - public function getRawPermissionValue(string $permission_name): int - { - if (!$this->isValidPermissionName($permission_name)) { - throw new InvalidArgumentException('No permission with the given name is existing!'); - } - - return $this->{$permission_name}; - } - - /** - * Sets the given permission to the value. - * - * @param string $permission_name the name of the permission to that should be set - * @param int $value The new value of the permissions - * - * @return $this - */ - public function setRawPermissionValue(string $permission_name, int $value): self - { - if (!$this->isValidPermissionName($permission_name)) { - throw new InvalidArgumentException(sprintf('No permission with the given name %s is existing!', $permission_name)); - } - - $this->{$permission_name} = $value; - - return $this; - } - - /** - * Sets multiple permissions at once. - * - * @param array $values An array in the form ['perm_name' => $value], containing the new data - * @param array|null $values2 if this array is not null, the first array will treated of list of perm names, - * and this array as an array of new values - * - * @return $this - */ - public function setRawPermissionValues(array $values, ?array $values2 = null): self - { - if (!empty($values2)) { - $values = array_combine($values, $values2); - } - - foreach ($values as $key => $value) { - $this->setRawPermissionValue($key, $value); - } - - return $this; - } - - /** - * Reads a bit pair from $data. - * - * @param int|string $data The data from where the bits should be extracted from - * @param int $n The number of the lower bit (of the pair) that should be read. Starting from zero. - * - * @return int the value of the bit pair - */ - final protected static function readBitPair($data, int $n): int - { - //Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.'); - if (0 !== $n % 2) { - throw new InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!'); - } - - $mask = 0b11 << $n; //Create a mask for the data - - return ($data & $mask) >> $n; //Apply mask and shift back - } - - /** - * Writes a bit pair in the given $data and returns it. - * - * @param int $data The data which should be modified - * @param int $n The number of the lower bit of the pair which should be written - * @param int $new The new value of the pair - * - * @return int the new data with the modified pair - */ - final protected static function writeBitPair(int $data, int $n, int $new): int - { - //Assert::lessThanEq($n, 31, '$n must be smaller than 32, because only a 32bit int is used! Got %s.'); - Assert::lessThanEq($new, 3, '$new must be smaller than 3, because a bit pair is written! Got %s.'); - Assert::greaterThanEq($new, 0, '$new must not be negative, because a bit pair is written! Got %s.'); - - if (0 !== $n % 2) { - throw new InvalidArgumentException('$n must be dividable by 2, because we address bit pairs here!'); - } - - $mask = 0b11 << $n; //Mask all bits that should be written - $newval = $new << $n; //The new value. - return ($data & ~$mask) | ($newval & $mask); - } -} diff --git a/src/Entity/UserSystem/User.php b/src/Entity/UserSystem/User.php index b651d679..72db01a4 100644 --- a/src/Entity/UserSystem/User.php +++ b/src/Entity/UserSystem/User.php @@ -207,11 +207,6 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe */ protected bool $need_pw_change = true; - /** - * //@ORM\Column(type="json"). - */ - //protected $roles = []; - /** * @var string|null The hashed password * @ORM\Column(type="string", nullable=true) @@ -265,11 +260,12 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe */ protected $currency; - /** @var PermissionsEmbed - * @ORM\Embedded(class="PermissionsEmbed", columnPrefix="perms_") + /** + * @var PermissionData * @ValidPermission() + * @ORM\Embedded(class="PermissionData", columnPrefix="permissions_") */ - protected $permissions; + protected PermissionData $permissions; /** * @var DateTime the time until the password reset token is valid @@ -280,7 +276,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe public function __construct() { parent::__construct(); - $this->permissions = new PermissionsEmbed(); + $this->permissions = new PermissionData(); $this->u2fKeys = new ArrayCollection(); $this->webauthn_keys = new ArrayCollection(); } @@ -427,7 +423,7 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe return $this; } - public function getPermissions(): PermissionsEmbed + public function getPermissions(): PermissionData { return $this->permissions; } diff --git a/src/Form/AdminPages/GroupAdminForm.php b/src/Form/AdminPages/GroupAdminForm.php index b8e9cfd1..2234a270 100644 --- a/src/Form/AdminPages/GroupAdminForm.php +++ b/src/Form/AdminPages/GroupAdminForm.php @@ -64,6 +64,7 @@ class GroupAdminForm extends BaseEntityAdminForm 'mapped' => false, 'data' => $builder->getData(), 'disabled' => !$this->security->isGranted('edit_permissions', $entity), + 'show_presets' => $this->security->isGranted('edit_permissions', $entity) && !$is_new, ]); } } diff --git a/src/Form/AttachmentFormType.php b/src/Form/AttachmentFormType.php index 2df31e20..041bebd7 100644 --- a/src/Form/AttachmentFormType.php +++ b/src/Form/AttachmentFormType.php @@ -106,7 +106,7 @@ class AttachmentFormType extends AbstractType 'required' => false, 'label' => 'attachment.edit.secure_file', 'mapped' => false, - 'disabled' => !$this->security->isGranted('@parts_attachments.show_private'), + 'disabled' => !$this->security->isGranted('@attachments.show_private'), 'help' => 'attachment.edit.secure_file.help', ]); diff --git a/src/Form/CollectionTypeExtension.php b/src/Form/CollectionTypeExtension.php index f3aa4143..8ca1b068 100644 --- a/src/Form/CollectionTypeExtension.php +++ b/src/Form/CollectionTypeExtension.php @@ -54,7 +54,7 @@ class CollectionTypeExtension extends AbstractTypeExtension public static function getExtendedTypes(): iterable { - return [CollectionType::class, WorkaroundCollectionType::class]; + return [CollectionType::class]; } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Form/Part/OrderdetailType.php b/src/Form/Part/OrderdetailType.php index 65dbde86..7010aff6 100644 --- a/src/Form/Part/OrderdetailType.php +++ b/src/Form/Part/OrderdetailType.php @@ -50,6 +50,7 @@ use App\Form\Type\StructuralEntityType; use App\Form\WorkaroundCollectionType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\Form\FormBuilderInterface; @@ -106,16 +107,15 @@ class OrderdetailType extends AbstractType } //Attachment section - $event->getForm()->add('pricedetails', WorkaroundCollectionType::class, [ + $event->getForm()->add('pricedetails', CollectionType::class, [ 'entry_type' => PricedetailType::class, - 'allow_add' => $this->security->isGranted('@parts_prices.create'), - 'allow_delete' => $this->security->isGranted('@parts_prices.delete'), + 'allow_add' => true, + 'allow_delete' => true, 'label' => false, 'reindex_enable' => true, 'prototype_data' => $dummy_pricedetail, 'by_reference' => false, 'entry_options' => [ - 'disabled' => !$this->security->isGranted('@parts_prices.edit'), 'measurement_unit' => $options['measurement_unit'], ], ]); diff --git a/src/Form/Part/PartBaseType.php b/src/Form/Part/PartBaseType.php index fba54dfb..bd30015a 100644 --- a/src/Form/Part/PartBaseType.php +++ b/src/Form/Part/PartBaseType.php @@ -103,7 +103,6 @@ class PartBaseType extends AbstractType 'attr' => [ 'placeholder' => 'part.edit.name.placeholder', ], - 'disabled' => !$this->security->isGranted('name.edit', $part), ]) ->add('description', RichTextEditorType::class, [ 'required' => false, @@ -114,7 +113,6 @@ class PartBaseType extends AbstractType 'placeholder' => 'part.edit.description.placeholder', 'rows' => 2, ], - 'disabled' => !$this->security->isGranted('description.edit', $part), ]) ->add('minAmount', SIUnitType::class, [ 'attr' => [ @@ -123,13 +121,11 @@ class PartBaseType extends AbstractType ], 'label' => 'part.edit.mininstock', 'measurement_unit' => $part->getPartUnit(), - 'disabled' => !$this->security->isGranted('minamount.edit', $part), ]) ->add('category', StructuralEntityType::class, [ 'class' => Category::class, 'label' => 'part.edit.category', 'disable_not_selectable' => true, - 'disabled' => !$this->security->isGranted('category.edit', $part), 'constraints' => [ ], ]) @@ -138,7 +134,6 @@ class PartBaseType extends AbstractType 'required' => false, 'label' => 'part.edit.footprint', 'disable_not_selectable' => true, - 'disabled' => !$this->security->isGranted('footprint.edit', $part), ]) ->add('tags', TextType::class, [ 'required' => false, @@ -149,7 +144,6 @@ class PartBaseType extends AbstractType 'data-controller' => 'elements--tagsinput', 'data-autocomplete' => $this->urlGenerator->generate('typeahead_tags', ['query' => '__QUERY__']), ], - 'disabled' => !$this->security->isGranted('tags.edit', $part), ]); //Manufacturer section @@ -158,32 +152,27 @@ class PartBaseType extends AbstractType 'required' => false, 'label' => 'part.edit.manufacturer.label', 'disable_not_selectable' => true, - 'disabled' => !$this->security->isGranted('manufacturer.edit', $part), ]) ->add('manufacturer_product_url', UrlType::class, [ 'required' => false, 'empty_data' => '', 'label' => 'part.edit.manufacturer_url.label', - 'disabled' => !$this->security->isGranted('mpn.edit', $part), ]) ->add('manufacturer_product_number', TextType::class, [ 'required' => false, 'empty_data' => '', 'label' => 'part.edit.mpn', - 'disabled' => !$this->security->isGranted('mpn.edit', $part), ]) ->add('manufacturing_status', ChoiceType::class, [ 'label' => 'part.edit.manufacturing_status', 'choices' => $status_choices, 'required' => false, - 'disabled' => !$this->security->isGranted('status.edit', $part), ]); //Advanced section $builder->add('needsReview', CheckboxType::class, [ 'required' => false, 'label' => 'part.edit.needs_review', - 'disabled' => !$this->security->isGranted('edit', $part), ]) ->add('favorite', CheckboxType::class, [ 'required' => false, @@ -194,14 +183,12 @@ class PartBaseType extends AbstractType 'unit' => 'g', 'label' => 'part.edit.mass', 'required' => false, - 'disabled' => !$this->security->isGranted('mass.edit', $part), ]) ->add('partUnit', StructuralEntityType::class, [ 'class' => MeasurementUnit::class, 'required' => false, 'disable_not_selectable' => true, 'label' => 'part.edit.partUnit', - 'disabled' => !$this->security->isGranted('unit.edit', $part), ]); //Comment section @@ -212,20 +199,18 @@ class PartBaseType extends AbstractType 'rows' => 4, ], 'mode' => 'markdown-full', - 'disabled' => !$this->security->isGranted('comment.edit', $part), 'empty_data' => '', ]); //Part Lots section $builder->add('partLots', CollectionType::class, [ 'entry_type' => PartLotType::class, - 'allow_add' => $this->security->isGranted('lots.create', $part), - 'allow_delete' => $this->security->isGranted('lots.delete', $part), + 'allow_add' => true, + 'allow_delete' => true, 'reindex_enable' => true, 'label' => false, 'entry_options' => [ 'measurement_unit' => $part->getPartUnit(), - 'disabled' => !$this->security->isGranted('lots.edit', $part), ], 'by_reference' => false, ]); @@ -233,49 +218,45 @@ class PartBaseType extends AbstractType //Attachment section $builder->add('attachments', CollectionType::class, [ 'entry_type' => AttachmentFormType::class, - 'allow_add' => $this->security->isGranted('attachments.create', $part), - 'allow_delete' => $this->security->isGranted('attachments.delete', $part), + 'allow_add' => true, + 'allow_delete' => true, 'reindex_enable' => true, 'label' => false, 'entry_options' => [ 'data_class' => PartAttachment::class, - 'disabled' => !$this->security->isGranted('attachments.edit', $part), ], 'by_reference' => false, ]); $builder->add('master_picture_attachment', MasterPictureAttachmentType::class, [ 'required' => false, - 'disabled' => !$this->security->isGranted('attachments.edit', $part), 'label' => 'part.edit.master_attachment', 'entity' => $part, ]); //Orderdetails section - $builder->add('orderdetails', WorkaroundCollectionType::class, [ + $builder->add('orderdetails', CollectionType::class, [ 'entry_type' => OrderdetailType::class, - 'allow_add' => $this->security->isGranted('orderdetails.create', $part), - 'allow_delete' => $this->security->isGranted('orderdetails.delete', $part), 'reindex_enable' => true, + 'allow_add' => true, + 'allow_delete' => true, 'label' => false, 'by_reference' => false, 'prototype_data' => new Orderdetail(), 'entry_options' => [ 'measurement_unit' => $part->getPartUnit(), - 'disabled' => !$this->security->isGranted('orderdetails.edit', $part), ], ]); $builder->add('parameters', CollectionType::class, [ 'entry_type' => ParameterType::class, - 'allow_add' => $this->security->isGranted('parameters.create', $part), - 'allow_delete' => $this->security->isGranted('parameters.delete', $part), + 'allow_add' => true, + 'allow_delete' => true, 'label' => false, 'reindex_enable' => true, 'by_reference' => false, 'prototype_data' => new PartParameter(), 'entry_options' => [ - 'disabled' => !$this->security->isGranted('parameters.edit', $part), 'data_class' => PartParameter::class, ], ]); diff --git a/src/Form/Permissions/PermissionGroupType.php b/src/Form/Permissions/PermissionGroupType.php index ee8ba628..8058ef43 100644 --- a/src/Form/Permissions/PermissionGroupType.php +++ b/src/Form/Permissions/PermissionGroupType.php @@ -42,7 +42,7 @@ declare(strict_types=1); namespace App\Form\Permissions; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; @@ -50,10 +50,10 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class PermissionGroupType extends AbstractType { - protected PermissionResolver $resolver; + protected PermissionManager $resolver; protected array $perm_structure; - public function __construct(PermissionResolver $resolver) + public function __construct(PermissionManager $resolver) { $this->resolver = $resolver; $this->perm_structure = $resolver->getPermissionStructure(); diff --git a/src/Form/Permissions/PermissionType.php b/src/Form/Permissions/PermissionType.php index d733417e..c95ca3ea 100644 --- a/src/Form/Permissions/PermissionType.php +++ b/src/Form/Permissions/PermissionType.php @@ -43,7 +43,7 @@ declare(strict_types=1); namespace App\Form\Permissions; use App\Form\Type\TriStateCheckboxType; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; @@ -53,10 +53,10 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class PermissionType extends AbstractType { - protected PermissionResolver $resolver; + protected PermissionManager $resolver; protected array $perm_structure; - public function __construct(PermissionResolver $resolver) + public function __construct(PermissionManager $resolver) { $this->resolver = $resolver; $this->perm_structure = $resolver->getPermissionStructure(); @@ -97,6 +97,9 @@ class PermissionType extends AbstractType 'mapped' => false, 'label' => $operation['label'] ?? null, 'disabled' => $options['disabled'], + 'attr' => [ + 'class' => 'permission-checkbox tristate', + ], 'label_attr' => [ 'class' => 'checkbox-inline opacity-100', ], diff --git a/src/Form/Permissions/PermissionsMapper.php b/src/Form/Permissions/PermissionsMapper.php index 6f637c3c..a188ce64 100644 --- a/src/Form/Permissions/PermissionsMapper.php +++ b/src/Form/Permissions/PermissionsMapper.php @@ -42,7 +42,7 @@ declare(strict_types=1); namespace App\Form\Permissions; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use RuntimeException; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\FormInterface; @@ -54,10 +54,10 @@ use Traversable; */ final class PermissionsMapper implements DataMapperInterface { - private PermissionResolver $resolver; + private PermissionManager $resolver; private bool $inherit; - public function __construct(PermissionResolver $resolver, bool $inherit = false) + public function __construct(PermissionManager $resolver, bool $inherit = false) { $this->inherit = $inherit; $this->resolver = $resolver; diff --git a/src/Form/Permissions/PermissionsType.php b/src/Form/Permissions/PermissionsType.php index b16e76e4..91ea03e3 100644 --- a/src/Form/Permissions/PermissionsType.php +++ b/src/Form/Permissions/PermissionsType.php @@ -42,7 +42,7 @@ declare(strict_types=1); namespace App\Form\Permissions; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use App\Validator\Constraints\NoLockout; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -53,10 +53,10 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class PermissionsType extends AbstractType { - protected PermissionResolver $resolver; + protected PermissionManager $resolver; protected array $perm_structure; - public function __construct(PermissionResolver $resolver) + public function __construct(PermissionManager $resolver) { $this->resolver = $resolver; $this->perm_structure = $resolver->getPermissionStructure(); @@ -66,6 +66,7 @@ class PermissionsType extends AbstractType { $resolver->setDefaults([ 'show_legend' => true, + 'show_presets' => false, 'constraints' => static function (Options $options) { if (!$options['disabled']) { return [new NoLockout()]; @@ -80,6 +81,7 @@ class PermissionsType extends AbstractType public function buildView(FormView $view, FormInterface $form, array $options): void { $view->vars['show_legend'] = $options['show_legend']; + $view->vars['show_presets'] = $options['show_presets']; } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/src/Form/UserAdminForm.php b/src/Form/UserAdminForm.php index 2c3d07c7..c2ca314e 100644 --- a/src/Form/UserAdminForm.php +++ b/src/Form/UserAdminForm.php @@ -102,7 +102,7 @@ class UserAdminForm extends AbstractType 'required' => false, 'label' => 'group.label', 'disable_not_selectable' => true, - 'disabled' => !$this->security->isGranted('change_group', $entity), + 'disabled' => !$this->security->isGranted('edit_permissions', $entity), ]) ->add('first_name', TextType::class, [ @@ -227,6 +227,7 @@ class UserAdminForm extends AbstractType 'mapped' => false, 'data' => $builder->getData(), 'disabled' => !$this->security->isGranted('edit_permissions', $entity), + 'show_presets' => $this->security->isGranted('edit_permissions', $entity) && !$is_new, ]) ; /*->add('comment', CKEditorType::class, ['required' => false, diff --git a/src/Form/WorkaroundCollectionType.php b/src/Form/WorkaroundCollectionType.php deleted file mode 100644 index 45bd0ba6..00000000 --- a/src/Form/WorkaroundCollectionType.php +++ /dev/null @@ -1,23 +0,0 @@ -vars['prototype']->vars['multipart']) { - $view->vars['multipart'] = true; - } - } -} diff --git a/src/Repository/NamedDBElementRepository.php b/src/Repository/NamedDBElementRepository.php index eb2348e4..6e6ee017 100644 --- a/src/Repository/NamedDBElementRepository.php +++ b/src/Repository/NamedDBElementRepository.php @@ -43,6 +43,7 @@ declare(strict_types=1); namespace App\Repository; use App\Entity\Base\AbstractNamedDBElement; +use App\Entity\UserSystem\User; use App\Helpers\Trees\TreeViewNode; class NamedDBElementRepository extends DBElementRepository @@ -63,6 +64,11 @@ class NamedDBElementRepository extends DBElementRepository $node = new TreeViewNode($entity->getName(), null, null); $node->setId($entity->getID()); $result[] = $node; + + if ($entity instanceof User && $entity->isDisabled()) { + //If this is an user, then add a badge when it is disabled + $node->setIcon('fa-fw fa-treeview fa-solid fa-user-lock text-muted'); + } } return $result; diff --git a/src/Security/Annotations/ColumnSecurity.php b/src/Security/Annotations/ColumnSecurity.php deleted file mode 100644 index dcc8881b..00000000 --- a/src/Security/Annotations/ColumnSecurity.php +++ /dev/null @@ -1,148 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Security\Annotations; - -use App\Entity\Base\AbstractNamedDBElement; -use DateTime; -use Doctrine\Common\Annotations\Annotation; -use Doctrine\Common\Collections\ArrayCollection; -use InvalidArgumentException; -use function is_string; - -/** - * @Annotation - * - * @Annotation\Target("PROPERTY") - * - * With these annotation you can restrict the access to certain coloumns in entities. - * The entity which should use this class has to use ElementListener as EntityListener. - */ -class ColumnSecurity -{ - /** - * @var string The name of the edit permission - */ - public string $edit = 'edit'; - /** - * @var string The name of the read permission - */ - public string $read = 'read'; - - /** - * @var string A prefix for all permission names (e.g..edit, useful for Parts) - */ - public string $prefix = ''; - - /** - * @var mixed the placeholder that should be used, when the access to the property is denied - */ - public $placeholder = null; - - public $subject = null; - - /** - * @var string The name of the property. This is used to determine the default placeholder. - * @Annotation\Enum({"integer", "string", "object", "boolean", "datetime", "collection"}) - */ - public $type = 'string'; - - public function getReadOperationName(): string - { - if ('' !== $this->prefix) { - return $this->prefix.'.'.$this->read; - } - - return $this->read; - } - - public function getEditOperationName(): string - { - if ('' !== $this->prefix) { - return $this->prefix.'.'.$this->edit; - } - - return $this->edit; - } - - public function getPlaceholder() - { - //Check if a class name was specified - if (class_exists($this->type)) { - $object = new $this->type(); - if ($object instanceof AbstractNamedDBElement) { - if (is_string($this->placeholder) && '' !== $this->placeholder) { - $object->setName($this->placeholder); - } else { - $object->setName('???'); - } - } - - return $object; - } - - if (null === $this->placeholder) { - switch ($this->type) { - case 'integer': - case 'int': - return 0; - case 'float': - return 0.0; - case 'string': - return '???'; - case 'object': - return null; - case 'collection': - return new ArrayCollection(); - case 'boolean': - case 'bool': - return false; - case 'datetime': - return (new DateTime())->setTimestamp(0); - default: - throw new InvalidArgumentException('Unknown type! You have to specify a placeholder!'); - } - } - - return $this->placeholder; - } -} diff --git a/src/Security/EntityListeners/ElementPermissionListener.php b/src/Security/EntityListeners/ElementPermissionListener.php deleted file mode 100644 index d9a8d90d..00000000 --- a/src/Security/EntityListeners/ElementPermissionListener.php +++ /dev/null @@ -1,223 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Security\EntityListeners; - -use App\Entity\Base\AbstractDBElement; -use App\Entity\UserSystem\User; -use App\Security\Annotations\ColumnSecurity; -use function count; -use Doctrine\Common\Annotations\Reader; -use Doctrine\ORM\Event\LifecycleEventArgs; -use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Event\PreFlushEventArgs; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\ORM\Mapping\PostLoad; -use function get_class; -use InvalidArgumentException; -use ReflectionClass; -use Symfony\Component\Security\Core\Security; - -/** - * The purpose of this class is to hook into the doctrine entity lifecycle and restrict access to entity informations - * configured by ColoumnSecurity Annotation. - * If the current programm is running from CLI (like a CLI command), the security checks are disabled. - * (Commands should be able to do everything they like). - * - * If a user does not have access to an coloumn, it will be filled, with a placeholder, after doctrine loading is finished. - * The edit process is also catched, so that these placeholders, does not get saved to database. - */ -class ElementPermissionListener -{ - protected Security $security; - protected Reader $reader; - protected EntityManagerInterface $em; - protected bool $disabled; - - protected array $perm_cache; - - public function __construct(Security $security, Reader $reader, EntityManagerInterface $em) - { - $this->security = $security; - $this->reader = $reader; - $this->em = $em; - //Disable security when the current program is running from CLI - $this->disabled = $this->isRunningFromCLI(); - $this->perm_cache = []; - } - - /** - * @PostLoad - * @ORM\PostUpdate() - * This function is called after doctrine filled, the entity properties with db values. - * We use this, to check if the user is allowed to access these properties, and if not, we write a placeholder - * into the element properties, so that a user only gets non sensitve data. - * - * This function is also called after an entity was updated, so we dont show the original data to user, - * after an update. - */ - public function postLoadHandler(AbstractDBElement $element, LifecycleEventArgs $event): void - { - //Do nothing if security is disabled - if ($this->disabled) { - return; - } - - //Read Annotations and properties. - $reflectionClass = new ReflectionClass($element); - $properties = $reflectionClass->getProperties(); - - foreach ($properties as $property) { - /** @var ColumnSecurity */ - $annotation = $this->reader->getPropertyAnnotation( - $property, - ColumnSecurity::class - ); - - //Check if user is allowed to read info, otherwise apply placeholder - if ((null !== $annotation) && !$this->isGranted('read', $annotation, $element)) { - $property->setAccessible(true); - $value = $annotation->getPlaceholder(); - - //Detach placeholder entities, so we dont get cascade errors - if ($value instanceof AbstractDBElement) { - $this->em->detach($value); - } - - $property->setValue($element, $value); - } - } - } - - /** - * @ORM\PreFlush() - * This function is called before flushing. We use it, to remove all placeholders. - * We do it here and not in preupdate, because this is called before calculating the changeset, - * and so we dont get problems with orphan removal. - */ - public function preFlushHandler(AbstractDBElement $element, PreFlushEventArgs $eventArgs): void - { - //Do nothing if security is disabled - if ($this->disabled) { - return; - } - - $unitOfWork = $eventArgs->getEntityManager()->getUnitOfWork(); - - $reflectionClass = new ReflectionClass($element); - $properties = $reflectionClass->getProperties(); - - $old_data = $unitOfWork->getOriginalEntityData($element); - - foreach ($properties as $property) { - $annotation = $this->reader->getPropertyAnnotation( - $property, - ColumnSecurity::class - ); - - $changed = false; - - //Only set the field if it has an annotation - if (null !== $annotation) { - $property->setAccessible(true); - - //If the user is not allowed to edit or read this property, reset all values. - //Set value to old value, so that there a no change to this property - if ((!$this->isGranted('read', $annotation, $element) - || !$this->isGranted('edit', $annotation, $element)) && isset( - $old_data[$property->getName()] - )) { - $property->setValue($element, $old_data[$property->getName()]); - $changed = true; - } - - if ($changed) { - //Schedule for update, so the post update method will be called - $unitOfWork->scheduleForUpdate($element); - } - } - } - } - - /** - * This function checks if the current script is run from web or from a terminal. - * - * @return bool Returns true if the current programm is running from CLI (terminal) - */ - protected function isRunningFromCLI(): bool - { - return empty($_SERVER['REMOTE_ADDR']) && !isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0; - } - - /** - * Checks if access to the property of the given element is granted. - * This function adds an additional cache layer, where the voters are called only once (to improve performance). - * - * @param string $mode What operation should be checked. Must be 'read' or 'edit' - * @param ColumnSecurity $annotation The annotation of the property that should be checked - * @param AbstractDBElement $element The element that should for which should be checked - * - * @return bool True if the user is allowed to read that property - */ - protected function isGranted(string $mode, ColumnSecurity $annotation, AbstractDBElement $element): bool - { - if ('read' === $mode) { - $operation = $annotation->getReadOperationName(); - } elseif ('edit' === $mode) { - $operation = $annotation->getEditOperationName(); - } else { - throw new InvalidArgumentException('$mode must be either "read" or "edit"!'); - } - - //Users must always be checked, because its return value can differ if it is the user itself or something else - if ($element instanceof User) { - return $this->security->isGranted($operation, $element); - } - - //Check if we have already have saved the permission, otherwise save it to cache - if (!isset($this->perm_cache[$mode][get_class($element)][$operation])) { - $this->perm_cache[$mode][get_class($element)][$operation] = $this->security->isGranted($operation, $element); - } - - return $this->perm_cache[$mode][get_class($element)][$operation]; - } -} diff --git a/src/Security/Interfaces/HasPermissionsInterface.php b/src/Security/Interfaces/HasPermissionsInterface.php index 323eef3e..10b0a31c 100644 --- a/src/Security/Interfaces/HasPermissionsInterface.php +++ b/src/Security/Interfaces/HasPermissionsInterface.php @@ -42,9 +42,9 @@ declare(strict_types=1); namespace App\Security\Interfaces; -use App\Entity\UserSystem\PermissionsEmbed; +use App\Entity\UserSystem\PermissionData; interface HasPermissionsInterface { - public function getPermissions(): PermissionsEmbed; + public function getPermissions(): PermissionData; } diff --git a/src/Security/UserChecker.php b/src/Security/UserChecker.php index bc51936b..a9b76a31 100644 --- a/src/Security/UserChecker.php +++ b/src/Security/UserChecker.php @@ -44,14 +44,19 @@ namespace App\Security; use App\Entity\UserSystem\User; use Symfony\Component\Security\Core\Exception\AccountStatusException; +use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Component\Security\Core\Exception\DisabledException; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Contracts\Translation\TranslatorInterface; final class UserChecker implements UserCheckerInterface { - public function __construct() + private TranslatorInterface $translator; + + public function __construct(TranslatorInterface $translator) { + $this->translator = $translator; } /** @@ -77,7 +82,8 @@ final class UserChecker implements UserCheckerInterface //Check if user is disabled. Then dont allow login if ($user->isDisabled()) { - throw new DisabledException(); + //throw new DisabledException(); + throw new CustomUserMessageAccountStatusException($this->translator->trans('user.login_error.user_disabled')); } } } diff --git a/src/Security/Voter/AttachmentVoter.php b/src/Security/Voter/AttachmentVoter.php index b5b7b7ba..e0ec23c1 100644 --- a/src/Security/Voter/AttachmentVoter.php +++ b/src/Security/Voter/AttachmentVoter.php @@ -44,10 +44,22 @@ namespace App\Security\Voter; use App\Entity\Attachments\Attachment; use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionManager; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; + use function in_array; class AttachmentVoter extends ExtendedVoter { + protected $security; + + public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + /** * Similar to voteOnAttribute, but checking for the anonymous user is already done. * The current user (or the anonymous user) is passed by $user. @@ -56,7 +68,31 @@ class AttachmentVoter extends ExtendedVoter */ protected function voteOnUser(string $attribute, $subject, User $user): bool { - return $this->resolver->inherit($user, 'parts_attachments', $attribute) ?? false; + //return $this->resolver->inherit($user, 'attachments', $attribute) ?? false; + + //If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element + $target_element = $subject->getElement(); + if (! $subject instanceof Attachment || null === $target_element) { + return false; + } + + //Depending on the operation delegate either to the attachments element or to the attachment permission + switch ($attribute) { + //We can view the attachment if we can view the element + case 'read': + case 'view': + return $this->security->isGranted('read', $target_element); + //We can edit/create/delete the attachment if we can edit the element + case 'edit': + case 'create': + case 'delete': + return $this->security->isGranted('edit', $target_element); + + case 'show_private': + return $this->resolver->inherit($user, 'attachments', 'show_private') ?? false; + } + + throw new \RuntimeException('Encountered unknown attribute "'.$attribute.'" in AttachmentVoter!'); } /** @@ -70,7 +106,8 @@ class AttachmentVoter extends ExtendedVoter protected function supports(string $attribute, $subject): bool { if (is_a($subject, Attachment::class, true)) { - return in_array($attribute, $this->resolver->listOperationsForPermission('parts_attachments'), false); + //These are the allowed attributes + return in_array($attribute, ['read', 'view', 'edit', 'delete', 'create', 'show_private'], true); } //Allow class name as subject diff --git a/src/Security/Voter/ExtendedVoter.php b/src/Security/Voter/ExtendedVoter.php index c7683efe..79743294 100644 --- a/src/Security/Voter/ExtendedVoter.php +++ b/src/Security/Voter/ExtendedVoter.php @@ -44,7 +44,7 @@ namespace App\Security\Voter; use App\Entity\UserSystem\User; use App\Repository\UserRepository; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\Voter; @@ -55,9 +55,9 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter; abstract class ExtendedVoter extends Voter { protected EntityManagerInterface $entityManager; - protected PermissionResolver $resolver; + protected PermissionManager $resolver; - public function __construct(PermissionResolver $resolver, EntityManagerInterface $entityManager) + public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager) { $this->resolver = $resolver; $this->entityManager = $entityManager; @@ -72,7 +72,7 @@ abstract class ExtendedVoter extends Voter return false; } - // if the user is anonymous, we use the anonymous user. + // if the user is anonymous (meaning $user is null), we use the anonymous user. if (!$user instanceof User) { /** @var UserRepository $repo */ $repo = $this->entityManager->getRepository(User::class); diff --git a/src/Security/Voter/OrderdetailVoter.php b/src/Security/Voter/OrderdetailVoter.php index 84a2b739..caebdcc0 100644 --- a/src/Security/Voter/OrderdetailVoter.php +++ b/src/Security/Voter/OrderdetailVoter.php @@ -25,30 +25,60 @@ namespace App\Security\Voter; use App\Entity\PriceInformations\Orderdetail; use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionManager; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class OrderdetailVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (! is_a($subject, Orderdetail::class, true)) { + throw new \RuntimeException('This voter can only handle Orderdetail objects!'); } - return $this->resolver->inherit($user, 'parts_orderdetails', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, Orderdetail::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_orderdetails') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false; diff --git a/src/Security/Voter/ParameterVoter.php b/src/Security/Voter/ParameterVoter.php new file mode 100644 index 00000000..8569b680 --- /dev/null +++ b/src/Security/Voter/ParameterVoter.php @@ -0,0 +1,113 @@ +security = $security; + parent::__construct($resolver, $entityManager); + } + + protected function voteOnUser(string $attribute, $subject, User $user): bool + { + //return $this->resolver->inherit($user, 'attachments', $attribute) ?? false; + + if (!$subject instanceof AbstractParameter) { + return false; + } + + //If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element + $target_element = $subject->getElement(); + if ($target_element !== null) { + //Depending on the operation delegate either to the attachments element or to the attachment permission + + + switch ($attribute) { + //We can view the attachment if we can view the element + case 'read': + case 'view': + $operation = 'read'; + break; + //We can edit/create/delete the attachment if we can edit the element + case 'edit': + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new RuntimeException('Unknown operation: '.$attribute); + } + + return $this->security->isGranted($operation, $target_element); + } + + //If we do not have a concrete element, we delegate to the different categories + if ($subject instanceof AttachmentTypeParameter) { + $param = 'attachment_types'; + } elseif ($subject instanceof CategoryParameter) { + $param = 'categories'; + } elseif ($subject instanceof CurrencyParameter) { + $param = 'currencies'; + } elseif ($subject instanceof DeviceParameter) { + $param = 'devices'; + } elseif ($subject instanceof FootprintParameter) { + $param = 'footprints'; + } elseif ($subject instanceof GroupParameter) { + $param = 'groups'; + } elseif ($subject instanceof ManufacturerParameter) { + $param = 'manufacturers'; + } elseif ($subject instanceof MeasurementUnitParameter) { + $param = 'measurement_units'; + } elseif ($subject instanceof PartParameter) { + $param = 'parts'; + } elseif ($subject instanceof StorelocationParameter) { + $param = 'storelocations'; + } elseif ($subject instanceof SupplierParameter) { + $param = 'suppliers'; + } else { + throw new RuntimeException('Encountered unknown Parameter type: ' . get_class($subject)); + } + + return $this->resolver->inherit($user, $param, $attribute) ?? false; + } + + protected function supports(string $attribute, $subject) + { + if (is_a($subject, AbstractParameter::class, true)) { + //These are the allowed attributes + return in_array($attribute, ['read', 'edit', 'delete', 'create', 'show_history', 'revert_element'], true); + } + + //Allow class name as subject + return false; + } +} \ No newline at end of file diff --git a/src/Security/Voter/PartLotVoter.php b/src/Security/Voter/PartLotVoter.php index 2fc8f608..d1e1f93d 100644 --- a/src/Security/Voter/PartLotVoter.php +++ b/src/Security/Voter/PartLotVoter.php @@ -25,30 +25,60 @@ namespace App\Security\Voter; use App\Entity\Parts\PartLot; use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionManager; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class PartLotVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (! is_a($subject, PartLot::class, true)) { + throw new \RuntimeException('This voter can only handle PartLot objects!'); } - return $this->resolver->inherit($user, 'parts_lots', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, PartLot::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_lots') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false; diff --git a/src/Security/Voter/PartVoter.php b/src/Security/Voter/PartVoter.php index cfbc66be..1470163e 100644 --- a/src/Security/Voter/PartVoter.php +++ b/src/Security/Voter/PartVoter.php @@ -57,13 +57,6 @@ class PartVoter extends ExtendedVoter protected function supports($attribute, $subject): bool { if (is_a($subject, Part::class, true)) { - //Check if a sub permission should be checked -> $attribute has format name.edit - if (false !== strpos($attribute, '.')) { - [$perm, $op] = explode('.', $attribute); - - return $this->resolver->isValidOperation('parts_'.$perm, $op); - } - return $this->resolver->isValidOperation('parts', $attribute); } @@ -73,13 +66,6 @@ class PartVoter extends ExtendedVoter protected function voteOnUser(string $attribute, $subject, User $user): bool { - //Check for sub permissions - if (false !== strpos($attribute, '.')) { - [$perm, $op] = explode('.', $attribute); - - return $this->resolver->inherit($user, 'parts_'.$perm, $op) ?? false; - } - //Null concealing operator means, that no return $this->resolver->inherit($user, 'parts', $attribute) ?? false; } diff --git a/src/Security/Voter/PermissionVoter.php b/src/Security/Voter/PermissionVoter.php index 7632d39d..729b5cfd 100644 --- a/src/Security/Voter/PermissionVoter.php +++ b/src/Security/Voter/PermissionVoter.php @@ -80,7 +80,14 @@ class PermissionVoter extends ExtendedVoter $attribute = ltrim($attribute, '@'); [$perm, $op] = explode('.', $attribute); - return $this->resolver->isValidOperation($perm, $op); + $valid = $this->resolver->isValidOperation($perm, $op); + + //if an invalid operation is encountered, throw an exception so the developer knows it + if(!$valid) { + throw new \RuntimeException('Encountered invalid permission operation "'.$op.'" for permission "'.$perm.'"!'); + } + + return true; } return false; diff --git a/src/Security/Voter/PricedetailVoter.php b/src/Security/Voter/PricedetailVoter.php index b21b367f..f4a55a42 100644 --- a/src/Security/Voter/PricedetailVoter.php +++ b/src/Security/Voter/PricedetailVoter.php @@ -25,30 +25,60 @@ namespace App\Security\Voter; use App\Entity\PriceInformations\Pricedetail; use App\Entity\UserSystem\User; +use App\Services\UserSystem\PermissionManager; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Security; class PricedetailVoter extends ExtendedVoter { - /** - * @var string[] When this permsission are encountered, they are checked on part - */ - protected const PART_PERMS = ['show_history', 'revert_element']; + protected Security $security; + + public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security) + { + parent::__construct($resolver, $entityManager); + $this->security = $security; + } + + protected const ALLOWED_PERMS = ['read', 'edit', 'create', 'delete', 'show_history', 'revert_element']; protected function voteOnUser(string $attribute, $subject, User $user): bool { - if (in_array($attribute, self::PART_PERMS, true)) { - return $this->resolver->inherit($user, 'parts', $attribute) ?? false; + if (!is_a($subject, Pricedetail::class, true)) { + throw new \RuntimeException('This voter can only handle Pricedetails objects!'); } - return $this->resolver->inherit($user, 'parts_prices', $attribute) ?? false; + switch ($attribute) { + case 'read': + $operation = 'read'; + break; + case 'edit': //As long as we can edit, we can also edit orderdetails + case 'create': + case 'delete': + $operation = 'edit'; + break; + case 'show_history': + $operation = 'show_history'; + break; + case 'revert_element': + $operation = 'revert_element'; + break; + default: + throw new \RuntimeException('Encountered unknown operation "'.$attribute.'"!'); + } + + //If we have no part associated use the generic part permission + if (is_string($subject) || $subject->getOrderdetail() === null || $subject->getOrderdetail()->getPart() === null) { + return $this->resolver->inherit($user, 'parts', $operation) ?? false; + } + + //Otherwise vote on the part + return $this->security->isGranted($attribute, $subject->getOrderdetail()->getPart()); } protected function supports($attribute, $subject): bool { if (is_a($subject, Pricedetail::class, true)) { - return in_array($attribute, array_merge( - self::PART_PERMS, - $this->resolver->listOperationsForPermission('parts_prices') - ), true); + return in_array($attribute, self::ALLOWED_PERMS, true); } return false; diff --git a/src/Services/Misc/DBInfoHelper.php b/src/Services/Misc/DBInfoHelper.php new file mode 100644 index 00000000..9180111c --- /dev/null +++ b/src/Services/Misc/DBInfoHelper.php @@ -0,0 +1,58 @@ +entityManager = $entityManager; + $this->connection = $entityManager->getConnection(); + } + + /** + * Returns the database type of the used database. + * @return string|null Returns 'mysql' for MySQL/MariaDB and 'sqlite' for SQLite. Returns null if unknown type + */ + public function getDatabaseType(): ?string + { + if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + return 'mysql'; + } + + if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + return 'sqlite'; + } + + return null; + } + + /** + * Returns the database version of the used database. + * @return string|null + * @throws \Doctrine\DBAL\Exception + */ + public function getDatabaseVersion(): ?string + { + if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) { + return $this->connection->fetchOne('SELECT VERSION()'); + } + + if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) { + return $this->connection->fetchOne('SELECT sqlite_version()'); + } + + return null; + } +} \ No newline at end of file diff --git a/src/Services/Parts/PartsTableActionHandler.php b/src/Services/Parts/PartsTableActionHandler.php index a30bd9d2..5fde6992 100644 --- a/src/Services/Parts/PartsTableActionHandler.php +++ b/src/Services/Parts/PartsTableActionHandler.php @@ -76,9 +76,11 @@ final class PartsTableActionHandler switch ($action) { case 'favorite': + $this->denyAccessUnlessGranted('change_favorite', $part); $part->setFavorite(true); break; case 'unfavorite': + $this->denyAccessUnlessGranted('change_favorite', $part); $part->setFavorite(false); break; case 'delete': @@ -86,19 +88,19 @@ final class PartsTableActionHandler $this->entityManager->remove($part); break; case 'change_category': - $this->denyAccessUnlessGranted('category.edit', $part); + $this->denyAccessUnlessGranted('@categories.read'); $part->setCategory($this->entityManager->find(Category::class, $target_id)); break; case 'change_footprint': - $this->denyAccessUnlessGranted('footprint.edit', $part); + $this->denyAccessUnlessGranted('@footprints.read'); $part->setFootprint(null === $target_id ? null : $this->entityManager->find(Footprint::class, $target_id)); break; case 'change_manufacturer': - $this->denyAccessUnlessGranted('manufacturer.edit', $part); + $this->denyAccessUnlessGranted('@manufacturers.read'); $part->setManufacturer(null === $target_id ? null : $this->entityManager->find(Manufacturer::class, $target_id)); break; case 'change_unit': - $this->denyAccessUnlessGranted('unit.edit', $part); + $this->denyAccessUnlessGranted('@measurement_units.read'); $part->setPartUnit(null === $target_id ? null : $this->entityManager->find(MeasurementUnit::class, $target_id)); break; diff --git a/src/Services/TranslationExtractor/PermissionExtractor.php b/src/Services/TranslationExtractor/PermissionExtractor.php index b7cb4c8d..11b2154b 100644 --- a/src/Services/TranslationExtractor/PermissionExtractor.php +++ b/src/Services/TranslationExtractor/PermissionExtractor.php @@ -42,7 +42,7 @@ declare(strict_types=1); namespace App\Services\TranslationExtractor; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Symfony\Component\Translation\Extractor\ExtractorInterface; use Symfony\Component\Translation\MessageCatalogue; @@ -55,7 +55,7 @@ final class PermissionExtractor implements ExtractorInterface private array $permission_structure; private bool $finished = false; - public function __construct(PermissionResolver $resolver) + public function __construct(PermissionManager $resolver) { $this->permission_structure = $resolver->getPermissionStructure(); } diff --git a/src/Services/Trees/ToolsTreeBuilder.php b/src/Services/Trees/ToolsTreeBuilder.php index 654e8d4e..831c3b0e 100644 --- a/src/Services/Trees/ToolsTreeBuilder.php +++ b/src/Services/Trees/ToolsTreeBuilder.php @@ -242,12 +242,15 @@ class ToolsTreeBuilder protected function getShowNodes(): array { $show_nodes = []; - $show_nodes[] = (new TreeViewNode( - $this->translator->trans('tree.tools.show.all_parts'), - $this->urlGenerator->generate('parts_show_all') - ))->setIcon('fa-fw fa-treeview fa-solid fa-globe'); - if ($this->security->isGranted('read', new PartAttachment())) { + if ($this->security->isGranted('@parts.read')) { + $show_nodes[] = (new TreeViewNode( + $this->translator->trans('tree.tools.show.all_parts'), + $this->urlGenerator->generate('parts_show_all') + ))->setIcon('fa-fw fa-treeview fa-solid fa-globe'); + } + + if ($this->security->isGranted('@attachments.list_attachments')) { $show_nodes[] = (new TreeViewNode( $this->translator->trans('tree.tools.show.all_attachments'), $this->urlGenerator->generate('attachment_list') @@ -291,6 +294,13 @@ class ToolsTreeBuilder ))->setIcon('fa-fw fa-treeview fa-solid fa-binoculars'); } + if ($this->security->isGranted('@system.server_infos')) { + $nodes[] = (new TreeViewNode( + $this->translator->trans('tools.server_infos.title'), + $this->urlGenerator->generate('tools_server_infos') + ))->setIcon('fa-fw fa-treeview fa-solid fa-database'); + } + return $nodes; } } diff --git a/src/Services/PasswordResetManager.php b/src/Services/UserSystem/PasswordResetManager.php similarity index 99% rename from src/Services/PasswordResetManager.php rename to src/Services/UserSystem/PasswordResetManager.php index 949afe6e..5a6aa29c 100644 --- a/src/Services/PasswordResetManager.php +++ b/src/Services/UserSystem/PasswordResetManager.php @@ -40,7 +40,7 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Services; +namespace App\Services\UserSystem; use App\Entity\UserSystem\User; use DateTime; @@ -50,7 +50,6 @@ use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Address; use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; - use Symfony\Component\PasswordHasher\PasswordHasherInterface; use Symfony\Contracts\Translation\TranslatorInterface; diff --git a/src/Services/PermissionResolver.php b/src/Services/UserSystem/PermissionManager.php similarity index 65% rename from src/Services/PermissionResolver.php rename to src/Services/UserSystem/PermissionManager.php index d6eedfb7..f665ee10 100644 --- a/src/Services/PermissionResolver.php +++ b/src/Services/UserSystem/PermissionManager.php @@ -40,7 +40,7 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Services; +namespace App\Services\UserSystem; use App\Configuration\PermissionsConfiguration; use App\Entity\UserSystem\Group; @@ -52,7 +52,12 @@ use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Yaml\Yaml; -class PermissionResolver +/** + * This class manages the permissions of users and groups. + * Permissions are defined in the config/permissions.yaml file, and are parsed and resolved by this class using the + * user and hierachical group PermissionData information. + */ +class PermissionManager { protected $permission_structure; @@ -81,6 +86,7 @@ class PermissionResolver * Check if a user/group is allowed to do the specified operation for the permission. * * See permissions.yaml for valid permission operation combinations. + * This function does not check, if the permission is valid! * * @param HasPermissionsInterface $user the user/group for which the operation should be checked * @param string $permission the name of the permission for which should be checked @@ -92,18 +98,13 @@ class PermissionResolver public function dontInherit(HasPermissionsInterface $user, string $permission, string $operation): ?bool { //Get the permissions from the user - $perm_list = $user->getPermissions(); - - //Determine bit number using our configuration - $bit = $this->permission_structure['perms'][$permission]['operations'][$operation]['bit']; - - return $perm_list->getPermissionValue($permission, $bit); + return $user->getPermissions()->getPermissionValue($permission, $operation); } /** * Checks if a user is allowed to do the specified operation for the permission. - * In contrast to dontInherit() it tries to resolve the inherit values, of the user, by going upwards in the - * hierachy (user -> group -> parent group -> so on). But even in this case it is possible, that the inherit value + * In contrast to dontInherit() it tries to resolve to inherit values, of the user, by going upwards in the + * hierarchy (user -> group -> parent group -> so on). But even in this case it is possible, that to inherit value * could be resolved, and this function returns null. * * In that case the voter should set it manually to false by using ?? false. @@ -153,10 +154,12 @@ class PermissionResolver //Get the permissions from the user $perm_list = $user->getPermissions(); - //Determine bit number using our configuration - $bit = $this->permission_structure['perms'][$permission]['operations'][$operation]['bit']; + //Check if the permission/operation combination is valid + if (! $this->isValidOperation($permission, $operation)) { + throw new InvalidArgumentException(sprintf('The permission/operation combination "%s.%s" is not valid!', $permission, $operation)); + } - $perm_list->setPermissionValue($permission, $bit, $new_val); + $perm_list->setPermissionValue($permission, $operation, $new_val); } /** @@ -206,13 +209,90 @@ class PermissionResolver isset($this->permission_structure['perms'][$permission]['operations'][$operation]); } + /** + * This functions sets all operations mentioned in the alsoSet value of a permission, so that the structure is always valid. + * @param HasPermissionsInterface $user + * @return void + */ + public function ensureCorrectSetOperations(HasPermissionsInterface $user): void + { + //If we have changed anything on the permission structure due to the alsoSet value, this becomes true, so we + //redo the whole process, to ensure that all alsoSet values are set recursively. + $anything_changed = false; + + do { + $anything_changed = false; //Reset the variable for the next iteration + + //Check for each permission and operation, for an alsoSet attribute + foreach ($this->permission_structure['perms'] as $perm_key => $permission) { + foreach ($permission['operations'] as $op_key => $op) { + if (!empty($op['alsoSet']) && + true === $this->dontInherit($user, $perm_key, $op_key)) { + //Set every op listed in also Set + foreach ($op['alsoSet'] as $set_also) { + //If the alsoSet value contains a dot then we set the operation of another permission + if (false !== strpos($set_also, '.')) { + [$set_perm, $set_op] = explode('.', $set_also); + } else { + //Else we set the operation of the same permission + [$set_perm, $set_op] = [$perm_key, $set_also]; + } + + //Check if we change the value of the permission + if ($this->dontInherit($user, $set_perm, $set_op) !== true) { + $this->setPermission($user, $set_perm, $set_op, true); + //Mark the change, so we redo the whole process + $anything_changed = true; + } + } + } + } + } + } while($anything_changed); + } + + /** + * Sets all possible operations of all possible permissions of the given entity to the given value. + * @param HasPermissionsInterface $perm_holder + * @param bool|null $new_value + * @return void + */ + public function setAllPermissions(HasPermissionsInterface $perm_holder, ?bool $new_value): void + { + foreach ($this->permission_structure['perms'] as $perm_key => $permission) { + foreach ($permission['operations'] as $op_key => $op) { + $this->setPermission($perm_holder, $perm_key, $op_key, $new_value); + } + } + } + + /** + * Sets all operations of the given permissions to the given value. + * Please note that you have to call ensureCorrectSetOperations() after this function, to ensure that all alsoSet values are set. + * + * @param HasPermissionsInterface $perm_holder + * @param string $permission + * @param bool|null $new_value + * @return void + */ + public function setAllOperationsOfPermission(HasPermissionsInterface $perm_holder, string $permission, ?bool $new_value): void + { + if (!$this->isValidPermission($permission)) { + throw new InvalidArgumentException(sprintf('A permission with that name is not existing! Got %s.', $permission)); + } + + foreach ($this->permission_structure['perms'][$permission]['operations'] as $op_key => $op) { + $this->setPermission($perm_holder, $permission, $op_key, $new_value); + } + } + protected function generatePermissionStructure() { $cache = new ConfigCache($this->cache_file, $this->is_debug); //Check if the cache is fresh, else regenerate it. if (!$cache->isFresh()) { - $permission_file = __DIR__.'/../../config/permissions.yaml'; + $permission_file = __DIR__.'/../../../config/permissions.yaml'; //Read the permission config file... $config = Yaml::parse( diff --git a/src/Services/UserSystem/PermissionPresetsHelper.php b/src/Services/UserSystem/PermissionPresetsHelper.php new file mode 100644 index 00000000..ebe3a0f9 --- /dev/null +++ b/src/Services/UserSystem/PermissionPresetsHelper.php @@ -0,0 +1,151 @@ +permissionResolver = $permissionResolver; + } + + /** + * Apply the given preset to the permission holding entity (like a user) + * The permission data will be reset during the process and then the preset will be applied. + * + * @param string $preset_name The name of the preset to use + * @return HasPermissionsInterface + */ + public function applyPreset(HasPermissionsInterface $perm_holder, string $preset_name): HasPermissionsInterface + { + //We need to reset the permission data first (afterwards all values are inherit) + $perm_holder->getPermissions()->resetPermissions(); + + switch($preset_name) { + case self::PRESET_ALL_INHERIT: + //Do nothing, all values are inherit after reset + break; + case self::PRESET_ALL_FORBID: + $this->allForbid($perm_holder); + break; + case self::PRESET_ALL_ALLOW: + $this->allAllow($perm_holder); + break; + case self::PRESET_READ_ONLY: + $this->readOnly($perm_holder); + break; + case self::PRESET_EDITOR: + $this->editor($perm_holder); + break; + case self::PRESET_ADMIN: + $this->admin($perm_holder); + break; + + default: + throw new \InvalidArgumentException('Unknown permission preset name: '.$preset_name); + } + + //Ensure that permissions are valid (alsoSet values are set), this allows us to use the permission inheritance system to keep the presets short + $this->permissionResolver->ensureCorrectSetOperations($perm_holder); + + return $perm_holder; + } + + private function admin(HasPermissionsInterface $perm_holder): void + { + //Apply everything from editor permission + $this->editor($perm_holder); + + //Allow user and group access + $this->permissionResolver->setAllOperationsOfPermission($perm_holder, 'users', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($perm_holder, 'groups', PermissionData::ALLOW); + + //Allow access to system log and server infos + $this->permissionResolver->setPermission($perm_holder, 'system', 'show_logs', PermissionData::ALLOW); + $this->permissionResolver->setPermission($perm_holder, 'system', 'server_infos', PermissionData::ALLOW); + } + + private function editor(HasPermissionsInterface $permHolder): HasPermissionsInterface + { + //Apply everything from read-only + $this->readOnly($permHolder); + + //Set datastructures + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'parts', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'categories', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'storelocations', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'footprints', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'manufacturers', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'attachment_types', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'currencies', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'measurement_units', PermissionData::ALLOW); + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'suppliers', PermissionData::ALLOW); + + //Attachments permissions + $this->permissionResolver->setPermission($permHolder, 'attachments', 'show_private', PermissionData::ALLOW); + + //Labels permissions (allow all except use twig) + $this->permissionResolver->setAllOperationsOfPermission($permHolder, 'labels', PermissionData::ALLOW); + $this->permissionResolver->setPermission($permHolder,'labels', 'use_twig', PermissionData::INHERIT); + + //Self permissions + $this->permissionResolver->setPermission($permHolder, 'self', 'edit_infos', PermissionData::ALLOW); + + //Various other permissions + $this->permissionResolver->setPermission($permHolder, 'tools', 'lastActivity', PermissionData::ALLOW); + + + return $permHolder; + } + + private function readOnly(HasPermissionsInterface $perm_holder): HasPermissionsInterface + { + //It is sufficient to only set the read operation to allow, read operations for datastructures are inherited + $this->permissionResolver->setPermission($perm_holder, 'parts', 'read', PermissionData::ALLOW); + + //Set tools permissions + $this->permissionResolver->setPermission($perm_holder, 'tools', 'statistics', PermissionData::ALLOW); + $this->permissionResolver->setPermission($perm_holder, 'tools', 'label_scanner', PermissionData::ALLOW); + $this->permissionResolver->setPermission($perm_holder, 'tools', 'reel_calculator', PermissionData::ALLOW); + + //Set attachments permissions + $this->permissionResolver->setPermission($perm_holder, 'attachments', 'list_attachments', PermissionData::ALLOW); + + //Set user (self) permissions + $this->permissionResolver->setPermission($perm_holder, 'self', 'show_permissions', PermissionData::ALLOW); + + //Label permissions + $this->permissionResolver->setPermission($perm_holder, 'labels', 'create_labels', PermissionData::ALLOW); + $this->permissionResolver->setPermission($perm_holder, 'labels', 'edit_options', PermissionData::ALLOW); + $this->permissionResolver->setPermission($perm_holder, 'labels', 'read_profiles', PermissionData::ALLOW); + + //Set devices permissions + $this->permissionResolver->setPermission($perm_holder, 'devices', 'read', PermissionData::ALLOW); + + return $perm_holder; + } + + private function AllForbid(HasPermissionsInterface $perm_holder): HasPermissionsInterface + { + $this->permissionResolver->setAllPermissions($perm_holder, PermissionData::DISALLOW); + return $perm_holder; + } + + private function AllAllow(HasPermissionsInterface $perm_holder): HasPermissionsInterface + { + $this->permissionResolver->setAllPermissions($perm_holder, PermissionData::ALLOW); + return $perm_holder; + } +} \ No newline at end of file diff --git a/src/Services/TFA/BackupCodeGenerator.php b/src/Services/UserSystem/TFA/BackupCodeGenerator.php similarity index 98% rename from src/Services/TFA/BackupCodeGenerator.php rename to src/Services/UserSystem/TFA/BackupCodeGenerator.php index 2c0b3479..e80b308b 100644 --- a/src/Services/TFA/BackupCodeGenerator.php +++ b/src/Services/UserSystem/TFA/BackupCodeGenerator.php @@ -40,7 +40,7 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Services\TFA; +namespace App\Services\UserSystem\TFA; use Exception; use RuntimeException; diff --git a/src/Services/TFA/BackupCodeManager.php b/src/Services/UserSystem/TFA/BackupCodeManager.php similarity index 98% rename from src/Services/TFA/BackupCodeManager.php rename to src/Services/UserSystem/TFA/BackupCodeManager.php index ae3cae17..4f7f6c24 100644 --- a/src/Services/TFA/BackupCodeManager.php +++ b/src/Services/UserSystem/TFA/BackupCodeManager.php @@ -40,7 +40,7 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Services\TFA; +namespace App\Services\UserSystem\TFA; use App\Entity\UserSystem\User; diff --git a/src/Validator/Constraints/NoLockoutValidator.php b/src/Validator/Constraints/NoLockoutValidator.php index cfe5ffb9..2407ff10 100644 --- a/src/Validator/Constraints/NoLockoutValidator.php +++ b/src/Validator/Constraints/NoLockoutValidator.php @@ -44,7 +44,7 @@ namespace App\Validator\Constraints; use App\Entity\UserSystem\Group; use App\Entity\UserSystem\User; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Security\Core\Security; @@ -53,12 +53,12 @@ use Symfony\Component\Validator\ConstraintValidator; class NoLockoutValidator extends ConstraintValidator { - protected PermissionResolver $resolver; + protected PermissionManager $resolver; protected array $perm_structure; protected Security $security; protected EntityManagerInterface $entityManager; - public function __construct(PermissionResolver $resolver, Security $security, EntityManagerInterface $entityManager) + public function __construct(PermissionManager $resolver, Security $security, EntityManagerInterface $entityManager) { $this->resolver = $resolver; $this->perm_structure = $resolver->getPermissionStructure(); diff --git a/src/Validator/Constraints/ValidPermissionValidator.php b/src/Validator/Constraints/ValidPermissionValidator.php index 54b84b21..4dd9992f 100644 --- a/src/Validator/Constraints/ValidPermissionValidator.php +++ b/src/Validator/Constraints/ValidPermissionValidator.php @@ -43,20 +43,19 @@ declare(strict_types=1); namespace App\Validator\Constraints; use App\Security\Interfaces\HasPermissionsInterface; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class ValidPermissionValidator extends ConstraintValidator { - protected PermissionResolver $resolver; + protected PermissionManager $resolver; protected array $perm_structure; - public function __construct(PermissionResolver $resolver) + public function __construct(PermissionManager $resolver) { $this->resolver = $resolver; - $this->perm_structure = $resolver->getPermissionStructure(); } /** @@ -74,17 +73,6 @@ class ValidPermissionValidator extends ConstraintValidator /** @var HasPermissionsInterface $perm_holder */ $perm_holder = $this->context->getObject(); - //Check for each permission and operation, for an alsoSet attribute - foreach ($this->perm_structure['perms'] as $perm_key => $permission) { - foreach ($permission['operations'] as $op_key => $op) { - if (!empty($op['alsoSet']) && - true === $this->resolver->dontInherit($perm_holder, $perm_key, $op_key)) { - //Set every op listed in also Set - foreach ($op['alsoSet'] as $set_also) { - $this->resolver->setPermission($perm_holder, $perm_key, $set_also, true); - } - } - } - } + $this->resolver->ensureCorrectSetOperations($perm_holder); } } diff --git a/templates/AdminPages/GroupAdmin.html.twig b/templates/AdminPages/GroupAdmin.html.twig index 409cb6d0..de88aab3 100644 --- a/templates/AdminPages/GroupAdmin.html.twig +++ b/templates/AdminPages/GroupAdmin.html.twig @@ -12,6 +12,7 @@ {% block additional_panes %}
+ {{ form_row(form.permissions) }}
{% endblock %} diff --git a/templates/Form/permissionLayout.html.twig b/templates/Form/permissionLayout.html.twig index b77b8f35..1e36b428 100644 --- a/templates/Form/permissionLayout.html.twig +++ b/templates/Form/permissionLayout.html.twig @@ -4,7 +4,7 @@ {% if multi_checkbox %}
- + @@ -48,26 +48,46 @@ {% block permissions_row %} {{ form_errors(form) }} - {% if show_legend %} -
- -
-
- - -
-
- - -
-
- - +
+ {% if show_legend %} +
+ +
+
+ + +
+
+ + +
+
+ + +
-
+ {% endif %} - {% endif %} + {% if show_presets %} +
+
+ + +
+
+ {% endif %} +
- {{ form_errors(form) }} @@ -93,8 +92,7 @@ {{ form_widget(form) }} - @@ -111,7 +109,7 @@ {{ form_widget(form) }} - diff --git a/templates/Parts/info/_extended_infos.html.twig b/templates/Parts/info/_extended_infos.html.twig index 8fdc18e1..97a375d7 100644 --- a/templates/Parts/info/_extended_infos.html.twig +++ b/templates/Parts/info/_extended_infos.html.twig @@ -9,7 +9,7 @@ {% trans %}user.creating_user{% endtrans %} - {% if is_granted('show_users', part) %} + {% if is_granted('show_history', part) %} {{ creating_user(part).fullName(true) ?? 'Unknown'|trans }} {% else %} {% trans %}accessDenied{% endtrans %} @@ -24,7 +24,7 @@ {% trans %}user.last_editing_user{% endtrans %} - {% if is_granted('show_users', part) %} + {% if is_granted('show_history', part) %} {{ last_editing_user(part).fullName(true) ?? 'Unknown'|trans }} {% else %} {% trans %}accessDenied{% endtrans %} diff --git a/templates/Tools/ServerInfos/_db.html.twig b/templates/Tools/ServerInfos/_db.html.twig new file mode 100644 index 00000000..7b7f1d99 --- /dev/null +++ b/templates/Tools/ServerInfos/_db.html.twig @@ -0,0 +1,13 @@ +{% import "helper.twig" as helper %} + + + + + + + + + + + +
Database type{{ db_type }}
Database Server Version{{ db_version }}
\ No newline at end of file diff --git a/templates/Tools/ServerInfos/_partdb.html.twig b/templates/Tools/ServerInfos/_partdb.html.twig new file mode 100644 index 00000000..5e5f6e3e --- /dev/null +++ b/templates/Tools/ServerInfos/_partdb.html.twig @@ -0,0 +1,66 @@ +{% import "helper.twig" as helper %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Part-DB Version{{ shivas_app_version }} {% if git_branch is not empty or git_commit is not empty %}({{ git_branch ?? '' }}/{{ git_commit ?? '' }}){% endif %}
Symfony environment{{ enviroment }} (Debug: {{ helper.boolean_badge(is_debug) }})
Part-DB Instance name{{ partdb_title }}
Default locale{{ default_locale | locale_name }} ({{ default_locale }})
Default timezone{{ default_timezone }}
Default Currency{{ default_currency | currency_name }} ({{ default_currency }}, {{ default_currency | currency_symbol }})
Default theme{{ default_theme | default('bootstrap') }}
Enabled locales{{ helper.array_to_tags(enabled_locales | map(l => "#{l|locale_name} (#{l})")) }}
Demo Mode{{ helper.boolean_badge(demo_mode) }}
GPDR Compliance Mode{{ helper.boolean_badge(gpdr_compliance) }}
Use Gravatar{{ helper.boolean_badge(use_gravatar) }}
Password Reset via Email enabled{{ helper.boolean_badge(email_password_reset) }}
Configured E-Mail sender{{ email_sender }} ({{ email_sender_name }})
Allow server-side download of attachments{{ helper.boolean_badge(allow_attachments_downloads) }}
Detailed error pages enabled{{ helper.boolean_badge(detailed_error_pages) }} (Admin Contact email: {{ error_page_admin_email }})
\ No newline at end of file diff --git a/templates/Tools/ServerInfos/_php.html.twig b/templates/Tools/ServerInfos/_php.html.twig new file mode 100644 index 00000000..4a9d8c4e --- /dev/null +++ b/templates/Tools/ServerInfos/_php.html.twig @@ -0,0 +1,25 @@ +{% import "helper.twig" as helper %} + + + + + + + + + + + + + + + + + + + + + + + +
PHP version{{ php_version }} (SAPI: {{ php_sapi }})
Server Operating System{{ php_uname }}
Opcache enabled{{ helper.boolean_badge(php_opcache_enabled) }}
Maximum upload sizee (upload_max_filesize / post_max_size){{ php_upload_max_filesize }} / {{ php_post_max_size }}
PHP extensions{{ helper.array_to_tags(php_extensions) }}
\ No newline at end of file diff --git a/templates/Tools/ServerInfos/main.html.twig b/templates/Tools/ServerInfos/main.html.twig new file mode 100644 index 00000000..02fcbad7 --- /dev/null +++ b/templates/Tools/ServerInfos/main.html.twig @@ -0,0 +1,30 @@ +{% extends "main_card.html.twig" %} + +{% block title %}{% trans %}tools.server_infos.title{% endtrans %}{% endblock %} + +{% block card_title %} + {% trans %}tools.server_infos.title{% endtrans %} +{% endblock %} + +{% block card_content %} + + + +

Run php bin/console partdb:check-requirements in a terminal in your Part-DB folder to check if there are any recommendations for your system configuration.

+{% endblock %} diff --git a/templates/_navbar.html.twig b/templates/_navbar.html.twig index 03e04632..56e57d0c 100644 --- a/templates/_navbar.html.twig +++ b/templates/_navbar.html.twig @@ -26,8 +26,9 @@ {% endif %} - - {% include "_navbar_search.html.twig" %} + {% if is_granted('@parts.read') %} + {% include "_navbar_search.html.twig" %} + {% endif %}
diff --git a/templates/components/tree_macros.html.twig b/templates/components/tree_macros.html.twig index 9cb8bdc7..db4ce4cb 100644 --- a/templates/components/tree_macros.html.twig +++ b/templates/components/tree_macros.html.twig @@ -1,13 +1,13 @@ {% macro sidebar_dropdown() %} - {# Format is [mode, route, label] #} + {# Format is [mode, route, label, show_condition] #} {% set data_sources = [ - ['categories', path('tree_category_root'), 'category.labelp'], - ['locations', path('tree_location_root'), 'storelocation.labelp'], - ['footprints', path('tree_footprint_root'), 'footprint.labelp'], - ['manufacturers', path('tree_manufacturer_root'), 'manufacturer.labelp'], - ['suppliers', path('tree_supplier_root'), 'supplier.labelp'], - ['devices', path('tree_device_root'), 'device.labelp'], - ['tools', path('tree_tools'), 'tools.label'], + ['categories', path('tree_category_root'), 'category.labelp', is_granted('@categories.read') and is_granted('@parts.read')], + ['locations', path('tree_location_root'), 'storelocation.labelp', is_granted('@storelocations.read') and is_granted('@parts.read')], + ['footprints', path('tree_footprint_root'), 'footprint.labelp', is_granted('@footprints.read') and is_granted('@parts.read')], + ['manufacturers', path('tree_manufacturer_root'), 'manufacturer.labelp', is_granted('@manufacturers.read') and is_granted('@parts.read')], + ['suppliers', path('tree_supplier_root'), 'supplier.labelp', is_granted('@suppliers.read') and is_granted('@parts.read')], + ['devices', path('tree_device_root'), 'device.labelp', is_granted('@devices.read')], + ['tools', path('tree_tools'), 'tools.label', true], ] %} @@ -17,9 +17,11 @@ {% for source in data_sources %} -
  • + {% if source[3] %} {# show_condition #} +
  • + {% endif %} {% endfor %} {% endmacro %} @@ -28,7 +30,7 @@
    + >Loading... / Access Denied diff --git a/templates/helper.twig b/templates/helper.twig index 07585599..4cfe1a11 100644 --- a/templates/helper.twig +++ b/templates/helper.twig @@ -6,6 +6,30 @@ {% endif %} {% endmacro %} +{% macro array_to_tags(tags, class="badge bg-primary") %} + {% for tag in tags %} + {{ tag | trim }} + {% endfor %} +{% endmacro %} + +{% macro bool_icon(bool) %} + {% if bool %} + + {% else %} + + {% endif %} +{% endmacro %} + +{% macro boolean_badge(value, class="badge") %} + {% if value %} + {% set class = class ~ ' bg-success' %} + {% else %} + {% set class = class ~ ' bg-danger' %} + {% endif %} + + {{ _self.bool_icon(value) }} {{ _self.boolean(value) }} +{% endmacro %} + {% macro string_to_tags(string, class="badge bg-info") %} {% for tag in string|split(',') %} {{ tag | trim }} @@ -106,21 +130,13 @@ {% endmacro %} -{% macro bool_icon(bool) %} - {% if bool %} - - {% else %} - - {% endif %} -{% endmacro %} - {% macro date_user_combination(entity, lastModified, datetime_format = "short") %} {% if lastModified == true %} {{ entity.lastModified | format_datetime(datetime_format) }} {% else %} {{ entity.addedDate | format_datetime(datetime_format) }} {% endif %} - {% if is_granted('show_users', entity) %} + {% if is_granted('show_history', entity) %} {% if lastModified == true %} {% set user = last_editing_user(entity) %} {% else %} @@ -129,9 +145,9 @@ {% if user is not null %} {% if user.fullName is not empty %} - ({{ user.fullName }}) + ({{ user.fullName }}) {% else %} - (@{{ user.name }}) + (@{{ user.name }}) {% endif %} {% endif %} {% endif %} diff --git a/tests/ApplicationAvailabilityFunctionalTest.php b/tests/ApplicationAvailabilityFunctionalTest.php index 3a5ce06f..cc3e5f66 100644 --- a/tests/ApplicationAvailabilityFunctionalTest.php +++ b/tests/ApplicationAvailabilityFunctionalTest.php @@ -71,13 +71,13 @@ class ApplicationAvailabilityFunctionalTest extends WebTestCase $client->request('GET', $url); - $this->assertTrue($client->getResponse()->isSuccessful(), 'Request not successful. Status code is '.$client->getResponse()->getStatusCode()); + $this->assertTrue($client->getResponse()->isSuccessful(), 'Request not successful. Status code is '.$client->getResponse()->getStatusCode() . ' for URL '.$url); } public function urlProvider(): ?Generator { //Homepage - //yield ['/']; + yield ['/']; //User related things yield ['/user/settings']; yield ['/user/info']; @@ -117,9 +117,21 @@ class ApplicationAvailabilityFunctionalTest extends WebTestCase //Statistics yield ['/statistics']; + //Event log + yield ['/log/']; //Slash suffix here is important + + //Typeahead yield ['/typeahead/builtInResources/search?query=DIP8']; yield ['/typeahead/tags/search/test']; + yield ['/typeahead/parameters/part/search/NPN']; + yield ['/typeahead/parameters/category/search/NPN']; + + //Select API + yield ['/select_api/category']; + yield ['/select_api/footprint']; + yield ['/select_api/manufacturer']; + yield ['/select_api/measurement_unit']; //Label test yield ['/scan']; @@ -130,5 +142,9 @@ class ApplicationAvailabilityFunctionalTest extends WebTestCase //Tools yield ['/tools/reel_calc']; + yield ['/tools/server_infos']; + + //Webauthn Register + yield ['/webauthn/register']; } } diff --git a/tests/DatatablesAvailabilityTest.php b/tests/DatatablesAvailabilityTest.php index 0ad3632a..96ee7a84 100644 --- a/tests/DatatablesAvailabilityTest.php +++ b/tests/DatatablesAvailabilityTest.php @@ -42,7 +42,7 @@ class DatatablesAvailabilityTest extends WebTestCase ]); $client->catchExceptions(false); $client->request('GET', $url); - $this->assertTrue($client->getResponse()->isSuccessful(), 'Request not successful. Status code is '.$client->getResponse()->getStatusCode()); + $this->assertTrue($client->getResponse()->isSuccessful(), 'Request not successful. Status code is '.$client->getResponse()->getStatusCode() . ' for URL '.$url); static::ensureKernelShutdown(); $client = static::createClient([], [ @@ -70,5 +70,9 @@ class DatatablesAvailabilityTest extends WebTestCase yield ['/log/']; yield ['/attachment/list']; + + //Test using filters + yield ['/category/1/parts?part_filter%5Bname%5D%5Boperator%5D=%3D&part_filter%5Bname%5D%5Bvalue%5D=BC547&part_filter%5Bcategory%5D%5Boperator%5D=INCLUDING_CHILDREN&part_filter%5Btags%5D%5Boperator%5D=ANY&part_filter%5Btags%5D%5Bvalue%5D=Test&part_filter%5Bsubmit%5D=']; + yield ['/category/1/parts?part_filter%5Bcategory%5D%5Boperator%5D=INCLUDING_CHILDREN&part_filter%5Bstorelocation%5D%5Boperator%5D=%3D&part_filter%5Bstorelocation%5D%5Bvalue%5D=1&part_filter%5BattachmentsCount%5D%5Boperator%5D=%3D&part_filter%5BattachmentsCount%5D%5Bvalue1%5D=3&part_filter%5Bsubmit%5D=']; } } diff --git a/tests/Entity/UserSystem/PermissionDataTest.php b/tests/Entity/UserSystem/PermissionDataTest.php new file mode 100644 index 00000000..a3e99f0f --- /dev/null +++ b/tests/Entity/UserSystem/PermissionDataTest.php @@ -0,0 +1,131 @@ +assertNull($perm_data->getPermissionValue('not_existing', 'not_existing')); + $this->assertFalse($perm_data->isPermissionSet('not_existing', 'not_existing')); + + $this->assertNull($perm_data->getPermissionValue('p1', 'op1')); + $this->assertNull($perm_data->getPermissionValue('p1', 'op2')); + $this->assertNull($perm_data->getPermissionValue('p2', 'op1')); + + //Set values + $perm_data->setPermissionValue('p1', 'op1', PermissionData::ALLOW); + $perm_data->setPermissionValue('p1', 'op2', PermissionData::DISALLOW); + $perm_data->setPermissionValue('p2', 'op1', PermissionData::ALLOW); + + //Check that values were set + $this->assertTrue($perm_data->isPermissionSet('p1', 'op1')); + $this->assertTrue($perm_data->isPermissionSet('p1', 'op2')); + $this->assertTrue($perm_data->isPermissionSet('p2', 'op1')); + + //Check that values are correct + $this->assertTrue($perm_data->getPermissionValue('p1', 'op1')); + $this->assertFalse($perm_data->getPermissionValue('p1', 'op2')); + $this->assertTrue($perm_data->getPermissionValue('p2', 'op1')); + + //Set values to null + $perm_data->setPermissionValue('p1', 'op1', null); + $this->assertNull($perm_data->getPermissionValue('p1', 'op1')); + //Values should be unset now + $this->assertFalse($perm_data->isPermissionSet('p1', 'op1')); + } + + public function testJSONSerialization() + { + $perm_data = new PermissionData(); + + $perm_data->setPermissionValue('perm1', 'op1', PermissionData::ALLOW); + $perm_data->setPermissionValue('perm1', 'op2', PermissionData::DISALLOW); + $perm_data->setPermissionValue('perm1', 'op3', PermissionData::ALLOW); + + $perm_data->setPermissionValue('perm2', 'op1', PermissionData::ALLOW); + $perm_data->setPermissionValue('perm2', 'op2', PermissionData::DISALLOW); + + //Ensure that JSON serialization works + $this->assertJsonStringEqualsJsonString(json_encode([ + 'perm1' => [ + 'op1' => true, + 'op2' => false, + 'op3' => true, + ], + 'perm2' => [ + 'op1' => true, + 'op2' => false, + ], + ], JSON_THROW_ON_ERROR), json_encode($perm_data, JSON_THROW_ON_ERROR)); + + //Set values to inherit to ensure they do not show up in the json + $perm_data->setPermissionValue('perm1', 'op3', null); + $perm_data->setPermissionValue('perm2', 'op1', null); + $perm_data->setPermissionValue('perm2', 'op2', null); + + //Ensure that JSON serialization works + $this->assertJsonStringEqualsJsonString(json_encode([ + 'perm1' => [ + 'op1' => true, + 'op2' => false, + ], + ], JSON_THROW_ON_ERROR), json_encode($perm_data, JSON_THROW_ON_ERROR)); + + } + + public function testFromJSON() + { + $json = json_encode([ + 'perm1' => [ + 'op1' => true, + 'op2' => false, + 'op3' => true, + ], + 'perm2' => [ + 'op1' => true, + 'op2' => false, + ], + ], JSON_THROW_ON_ERROR); + + $perm_data = PermissionData::fromJSON($json); + + //Ensure that values were set correctly + $this->assertTrue($perm_data->getPermissionValue('perm1', 'op1')); + $this->assertFalse($perm_data->getPermissionValue('perm2', 'op2')); + } + + public function testResetPermissions() + { + $data = new PermissionData(); + + $data->setPermissionValue('perm1', 'op1', PermissionData::ALLOW); + $data->setPermissionValue('perm1', 'op2', PermissionData::DISALLOW); + $data->setPermissionValue('perm1', 'op3', PermissionData::INHERIT); + + //Ensure that values were set correctly + $this->assertTrue($data->isPermissionSet('perm1', 'op1')); + $this->assertTrue($data->isPermissionSet('perm1', 'op2')); + $this->assertFalse($data->isPermissionSet('perm1', 'op3')); + + //Reset the permissions + $data->resetPermissions(); + + //Afterwards all values must be set to inherit (null) + $this->assertNull($data->getPermissionValue('perm1', 'op1')); + $this->assertNull($data->getPermissionValue('perm1', 'op2')); + $this->assertNull($data->getPermissionValue('perm1', 'op3')); + + //And be undefined + $this->assertFalse($data->isPermissionSet('perm1', 'op1')); + $this->assertFalse($data->isPermissionSet('perm1', 'op2')); + $this->assertFalse($data->isPermissionSet('perm1', 'op3')); + } +} diff --git a/tests/Entity/UserSystem/PermissionsEmbedTest.php b/tests/Entity/UserSystem/PermissionsEmbedTest.php deleted file mode 100644 index 92d61e92..00000000 --- a/tests/Entity/UserSystem/PermissionsEmbedTest.php +++ /dev/null @@ -1,211 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Tests\Entity\UserSystem; - -use App\Entity\UserSystem\PermissionsEmbed; -use InvalidArgumentException; -use PHPUnit\Framework\TestCase; -use ReflectionClass; - -class PermissionsEmbedTest extends TestCase -{ - public function testGetPermissionValue(): void - { - $embed = new PermissionsEmbed(); - //For newly created embedded, all things should be set to inherit => null - //Test both normal name and constants - - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::CONFIG, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::ATTACHMENT_TYPES, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::CATEGORIES, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::DATABASE, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::DEVICE_PARTS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::DEVICES, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::FOOTRPINTS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::GROUPS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::DATABASE, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::LABELS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::MANUFACTURERS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_ATTACHMENTS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_COMMENT, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_DESCRIPTION, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_FOOTPRINT, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_MANUFACTURER, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_MINAMOUNT, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_NAME, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_ORDER, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS_ORDERDETAILS, 0)); - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::USERS, 0)); - - //Set a value for testing to the part property - $reflection = new ReflectionClass($embed); - $property = $reflection->getProperty('parts'); - $property->setAccessible(true); - - $property->setValue($embed, 0b11011000); // 11 01 10 00 - - //Test if function is working correctly - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS, 0)); - $this->assertFalse($embed->getPermissionValue(PermissionsEmbed::PARTS, 2)); - $this->assertTrue($embed->getPermissionValue(PermissionsEmbed::PARTS, 4)); - // 11 is reserved, but it should be also treat as INHERIT. - $this->assertNull($embed->getPermissionValue(PermissionsEmbed::PARTS, 6)); - } - - public function testGetBitValue(): void - { - $embed = new PermissionsEmbed(); - - //Set a value for testing to the part property - $reflection = new ReflectionClass($embed); - $property = $reflection->getProperty('parts'); - $property->setAccessible(true); - - $property->setValue($embed, 0b11011000); // 11 01 10 00 - - //Test if function is working correctly - $this->assertSame(PermissionsEmbed::INHERIT, $embed->getBitValue(PermissionsEmbed::PARTS, 0)); - $this->assertSame(PermissionsEmbed::DISALLOW, $embed->getBitValue(PermissionsEmbed::PARTS, 2)); - $this->assertSame(PermissionsEmbed::ALLOW, $embed->getBitValue(PermissionsEmbed::PARTS, 4)); - // 11 is reserved, but it should be also treat as INHERIT. - $this->assertSame(0b11, $embed->getBitValue(PermissionsEmbed::PARTS, 6)); - } - - public function testInvalidPermissionName(): void - { - $embed = new PermissionsEmbed(); - //When encoutering an unknown permission name the class must throw an exception - $this->expectException(InvalidArgumentException::class); - $embed->getPermissionValue('invalid', 0); - } - - public function testInvalidBit1(): void - { - $embed = new PermissionsEmbed(); - //When encoutering an negative bit the class must throw an exception - $this->expectException(InvalidArgumentException::class); - $embed->getPermissionValue('parts', -1); - } - - public function testInvalidBit2(): void - { - $embed = new PermissionsEmbed(); - //When encoutering an odd bit number it must throw an error. - $this->expectException(InvalidArgumentException::class); - $embed->getPermissionValue('parts', 1); - } - - public function getStatesBINARY(): array - { - return [ - 'ALLOW' => [PermissionsEmbed::ALLOW], - 'DISALLOW' => [PermissionsEmbed::DISALLOW], - 'INHERIT' => [PermissionsEmbed::INHERIT], - '0b11' => [0b11], - ]; - } - - public function getStatesBOOL(): array - { - return [ - 'ALLOW' => [true], - 'DISALLOW' => [false], - 'INHERIT' => [null], - '0b11' => [null], - ]; - } - - /** - * @dataProvider getStatesBINARY - */ - public function testTestsetBitValue($value): void - { - $embed = new PermissionsEmbed(); - //Check if it returns itself, for chaining. - $this->assertSame($embed, $embed->setBitValue(PermissionsEmbed::PARTS, 0, $value)); - $this->assertSame($value, $embed->getBitValue(PermissionsEmbed::PARTS, 0)); - } - - /** - * @dataProvider getStatesBOOL - */ - public function testSetPermissionValue($value): void - { - $embed = new PermissionsEmbed(); - //Check if it returns itself, for chaining. - $this->assertSame($embed, $embed->setPermissionValue(PermissionsEmbed::PARTS, 0, $value)); - $this->assertSame($value, $embed->getPermissionValue(PermissionsEmbed::PARTS, 0)); - } - - public function testSetRawPermissionValue(): void - { - $embed = new PermissionsEmbed(); - $embed->setRawPermissionValue(PermissionsEmbed::PARTS, 10); - $this->assertSame(10, $embed->getRawPermissionValue(PermissionsEmbed::PARTS)); - } - - public function testSetRawPermissionValues(): void - { - $embed = new PermissionsEmbed(); - $embed->setRawPermissionValues([ - PermissionsEmbed::PARTS => 0, - PermissionsEmbed::USERS => 100, - PermissionsEmbed::CATEGORIES => 1304, - ]); - - $this->assertSame(0, $embed->getRawPermissionValue(PermissionsEmbed::PARTS)); - $this->assertSame(100, $embed->getRawPermissionValue(PermissionsEmbed::USERS)); - $this->assertSame(1304, $embed->getRawPermissionValue(PermissionsEmbed::CATEGORIES)); - - //Test second method to pass perm names and values - $embed->setRawPermissionValues( - [PermissionsEmbed::PARTS, PermissionsEmbed::USERS, PermissionsEmbed::CATEGORIES], - [0, 100, 1304] - ); - - $this->assertSame(0, $embed->getRawPermissionValue(PermissionsEmbed::PARTS)); - $this->assertSame(100, $embed->getRawPermissionValue(PermissionsEmbed::USERS)); - $this->assertSame(1304, $embed->getRawPermissionValue(PermissionsEmbed::CATEGORIES)); - } -} diff --git a/tests/Security/Annotations/ColumnSecurityTest.php b/tests/Security/Annotations/ColumnSecurityTest.php deleted file mode 100644 index b6cd7f78..00000000 --- a/tests/Security/Annotations/ColumnSecurityTest.php +++ /dev/null @@ -1,127 +0,0 @@ -. - */ - -declare(strict_types=1); - -/** - * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony). - * - * Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -namespace App\Tests\Security\Annotations; - -use App\Entity\Attachments\AttachmentType; -use App\Security\Annotations\ColumnSecurity; -use PHPUnit\Framework\TestCase; - -class ColumnSecurityTest extends TestCase -{ - public function testGetReadOperation(): void - { - $annotation = new ColumnSecurity(); - $this->assertSame('read', $annotation->getReadOperationName(), 'A new annotation must return read'); - $annotation->read = 'overwritten'; - $this->assertSame('overwritten', $annotation->getReadOperationName()); - $annotation->prefix = 'prefix'; - $this->assertSame('prefix.overwritten', $annotation->getReadOperationName()); - } - - public function testGetEditOperation(): void - { - $annotation = new ColumnSecurity(); - $this->assertSame('edit', $annotation->getEditOperationName(), 'A new annotation must return read'); - $annotation->edit = 'overwritten'; - $this->assertSame('overwritten', $annotation->getEditOperationName()); - $annotation->prefix = 'prefix'; - $this->assertSame('prefix.overwritten', $annotation->getEditOperationName()); - } - - public function placeholderScalarDataProvider(): array - { - return [ - ['string', '???'], - ['integer', 0], - ['int', 0], - ['float', 0.0], - ['object', null], - ['bool', false], - ['boolean', false], - //['datetime', (new \DateTime())->setTimestamp(0)] - ]; - } - - /** - * @dataProvider placeholderScalarDataProvider - * - * @param $expected_value - */ - public function testGetPlaceholderScalar(string $type, $expected_value): void - { - $annotation = new ColumnSecurity(); - $annotation->type = $type; - $this->assertSame($expected_value, $annotation->getPlaceholder()); - } - - public function testGetPlaceholderSpecifiedValue(): void - { - $annotation = new ColumnSecurity(); - $annotation->placeholder = 3434; - $this->assertSame(3434, $annotation->getPlaceholder()); - - $annotation->placeholder = [323]; - $this->assertCount(1, $annotation->getPlaceholder()); - - //If a placeholder is specified we allow every type - $annotation->type = 'type2'; - $annotation->placeholder = 'invalid'; - $this->assertSame('invalid', $annotation->getPlaceholder()); - } - - public function testGetPlaceholderDBElement(): void - { - $annotation = new ColumnSecurity(); - $annotation->type = AttachmentType::class; - - /** @var AttachmentType $placeholder */ - $placeholder = $annotation->getPlaceholder(); - $this->assertInstanceOf(AttachmentType::class, $placeholder); - $this->assertSame('???', $placeholder->getName()); - - $annotation->placeholder = 'test'; - $placeholder = $annotation->getPlaceholder(); - $this->assertInstanceOf(AttachmentType::class, $placeholder); - $this->assertSame('test', $placeholder->getName()); - } -} diff --git a/tests/Security/UserCheckerTest.php b/tests/Security/UserCheckerTest.php index 4b61699e..608d6443 100644 --- a/tests/Security/UserCheckerTest.php +++ b/tests/Security/UserCheckerTest.php @@ -45,15 +45,18 @@ namespace App\Tests\Security; use App\Entity\UserSystem\User; use App\Security\UserChecker; use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException; use Symfony\Component\Security\Core\Exception\DisabledException; -class UserCheckerTest extends TestCase +class UserCheckerTest extends WebTestCase { protected $service; protected function setUp(): void { - $this->service = new UserChecker(); + self::bootKernel(); + $this->service = self::getContainer()->get(UserChecker::class); } public function testThrowDisabledException(): void @@ -66,7 +69,7 @@ class UserCheckerTest extends TestCase //An disabled user must throw an exception $user->setDisabled(true); - $this->expectException(DisabledException::class); + $this->expectException(CustomUserMessageAccountStatusException::class); $this->service->checkPostAuth($user); } } diff --git a/tests/Services/PermissionResolverTest.php b/tests/Services/UserSystem/PermissionManagerTest.php similarity index 54% rename from tests/Services/PermissionResolverTest.php rename to tests/Services/UserSystem/PermissionManagerTest.php index 1ca02b6d..7255ab41 100644 --- a/tests/Services/PermissionResolverTest.php +++ b/tests/Services/UserSystem/PermissionManagerTest.php @@ -40,23 +40,25 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Tests\Services; +namespace App\Tests\Services\UserSystem; use App\Entity\UserSystem\Group; +use App\Entity\UserSystem\PermissionData; use App\Entity\UserSystem\PermissionsEmbed; use App\Entity\UserSystem\User; -use App\Services\PermissionResolver; +use App\Services\UserSystem\PermissionManager; use InvalidArgumentException; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -class PermissionResolverTest extends WebTestCase +class PermissionManagerTest extends WebTestCase { protected $user_withoutGroup; protected $user; protected $group; + /** - * @var PermissionResolver + * @var PermissionManager */ protected $service; @@ -66,75 +68,58 @@ class PermissionResolverTest extends WebTestCase //Get an service instance. self::bootKernel(); - $this->service = self::$container->get(PermissionResolver::class); + $this->service = self::getContainer()->get(PermissionManager::class); //Set up a mocked user - $user_embed = new PermissionsEmbed(); - $user_embed->setPermissionValue('parts', 0, true) //read - ->setPermissionValue('parts', 2, false) //edit - ->setPermissionValue('parts', 4, null) //create - ->setPermissionValue('parts', 30, null) //move - ->setPermissionValue('parts', 8, null); //delete + $user_perms = new PermissionData(); + $user_perms->setPermissionValue('parts', 'read', true) //read + ->setPermissionValue('parts', 'edit', false) //edit + ->setPermissionValue('parts', 'create', null) //create + ->setPermissionValue('parts', 'move', null) //move + ->setPermissionValue('parts', 'delete', null); //delete $this->user = $this->createMock(User::class); - $this->user->method('getPermissions')->willReturn($user_embed); + $this->user->method('getPermissions')->willReturn($user_perms); $this->user_withoutGroup = $this->createMock(User::class); - $this->user_withoutGroup->method('getPermissions')->willReturn($user_embed); + $this->user_withoutGroup->method('getPermissions')->willReturn($user_perms); $this->user_withoutGroup->method('getGroup')->willReturn(null); //Set up a faked group - $group1_embed = new PermissionsEmbed(); - $group1_embed->setPermissionValue('parts', 6, true) - ->setPermissionValue('parts', 8, false) - ->setPermissionValue('parts', 10, null) - ->setPermissionValue('parts', 0, false) - ->setPermissionValue('parts', 30, true) - ->setPermissionValue('parts', 2, true); + $group1_perms = new PermissionData(); + $group1_perms + ->setPermissionValue('parts', 'delete', false) + ->setPermissionValue('parts', 'search', null) + ->setPermissionValue('parts', 'read', false) + ->setPermissionValue('parts', 'show_history', true) + ->setPermissionValue('parts', 'edit', true); $this->group = $this->createMock(Group::class); - $this->group->method('getPermissions')->willReturn($group1_embed); + $this->group->method('getPermissions')->willReturn($group1_perms); //Set this group for the user $this->user->method('getGroup')->willReturn($this->group); //parent group - $parent_group_embed = new PermissionsEmbed(); - $parent_group_embed->setPermissionValue('parts', 12, true) - ->setPermissionValue('parts', 14, false) - ->setPermissionValue('parts', 16, null); + $parent_group_perms = new PermissionData(); + $parent_group_perms->setPermissionValue('parts', 'all_parts', true) + ->setPermissionValue('parts', 'no_price_parts', false) + ->setPermissionValue('parts', 'obsolete_parts', null); $parent_group = $this->createMock(Group::class); - $parent_group->method('getPermissions')->willReturn($parent_group_embed); + $parent_group->method('getPermissions')->willReturn($parent_group_perms); $this->group->method('getParent')->willReturn($parent_group); } public function getPermissionNames(): array { - //List all possible operation names. + //List some permission names return [ - [PermissionsEmbed::PARTS], - [PermissionsEmbed::USERS], - [PermissionsEmbed::PARTS_ORDERDETAILS], - [PermissionsEmbed::PARTS_NAME], - [PermissionsEmbed::PARTS_ORDER], - [PermissionsEmbed::PARTS_MINAMOUNT], - [PermissionsEmbed::PARTS_MANUFACTURER], - [PermissionsEmbed::DEVICES], - [PermissionsEmbed::PARTS_FOOTPRINT], - [PermissionsEmbed::PARTS_DESCRIPTION], - [PermissionsEmbed::PARTS_COMMENT], - [PermissionsEmbed::PARTS_ATTACHMENTS], - [PermissionsEmbed::MANUFACTURERS], - [PermissionsEmbed::LABELS], - [PermissionsEmbed::DATABASE], - [PermissionsEmbed::GROUPS], - [PermissionsEmbed::FOOTRPINTS], - [PermissionsEmbed::DEVICE_PARTS], - [PermissionsEmbed::CATEGORIES], - [PermissionsEmbed::PARTS_PRICES], - [PermissionsEmbed::ATTACHMENT_TYPES], - [PermissionsEmbed::CONFIG], + ['parts'], + ['system'], + ['footprints'], + ['suppliers'], + ['tools'] ]; } @@ -214,4 +199,96 @@ class PermissionResolverTest extends WebTestCase $this->assertNull($this->service->inherit($this->user_withoutGroup, 'parts', 'show_history')); $this->assertNull($this->service->inherit($this->user_withoutGroup, 'parts', 'delete')); } + + public function testSetPermission(): void + { + $user = new User(); + + //Set permission to true + $this->service->setPermission($user, 'parts', 'read', true); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'read')); + $this->assertTrue($this->service->inherit($user, 'parts', 'read')); + + //Set permission to false + $this->service->setPermission($user, 'parts', 'read', false); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'read')); + $this->assertFalse($this->service->inherit($user, 'parts', 'read')); + + //Set permission to null + $this->service->setPermission($user, 'parts', 'read', null); + $this->assertNull($this->service->dontInherit($user, 'parts', 'read')); + $this->assertNull($this->service->inherit($user, 'parts', 'read')); + } + + public function testSetAllPermissions(): void + { + $user = new User(); + + //Set all permissions to true + $this->service->setAllPermissions($user, true); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'read')); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'create')); + $this->assertTrue($this->service->dontInherit($user, 'categories', 'edit')); + + //Set all permissions to false + $this->service->setAllPermissions($user, false); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'read')); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'create')); + $this->assertFalse($this->service->dontInherit($user, 'categories', 'edit')); + + //Set all permissions to null + $this->service->setAllPermissions($user, null); + $this->assertNull($this->service->dontInherit($user, 'parts', 'read')); + $this->assertNull($this->service->dontInherit($user, 'parts', 'create')); + $this->assertNull($this->service->dontInherit($user, 'categories', 'edit')); + } + + public function testSetAllOperationsOfPermission(): void + { + $user = new User(); + + //Set all operations of permission to true + $this->service->setAllOperationsOfPermission($user, 'parts', true); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'read')); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'create')); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'edit')); + + //Set all operations of permission to false + $this->service->setAllOperationsOfPermission($user, 'parts', false); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'read')); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'create')); + $this->assertFalse($this->service->dontInherit($user, 'parts', 'edit')); + + //Set all operations of permission to null + $this->service->setAllOperationsOfPermission($user, 'parts', null); + $this->assertNull($this->service->dontInherit($user, 'parts', 'read')); + $this->assertNull($this->service->dontInherit($user, 'parts', 'create')); + $this->assertNull($this->service->dontInherit($user, 'parts', 'edit')); + } + + public function testEnsureCorrectSetOperations(): void + { + //Create an empty user (all permissions are inherit) + $user = new User(); + + //ensure that all permissions are inherit + $this->assertNull($this->service->inherit($user, 'parts', 'read')); + $this->assertNull($this->service->inherit($user, 'parts', 'edit')); + $this->assertNull($this->service->inherit($user, 'categories', 'read')); + + //Set some permissions + $this->service->setPermission($user, 'parts', 'create', true); + //Until now only the create permission should be set + $this->assertTrue($this->service->dontInherit($user, 'parts', 'create')); + $this->assertNull($this->service->dontInherit($user, 'parts', 'read')); + + //Now we call the ensureCorrectSetOperations method + $this->service->ensureCorrectSetOperations($user); + + //Now all permissions should be set + $this->assertTrue($this->service->dontInherit($user, 'parts', 'create')); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'read')); + $this->assertTrue($this->service->dontInherit($user, 'parts', 'edit')); + $this->assertTrue($this->service->dontInherit($user, 'categories', 'read')); + } } diff --git a/tests/Services/TFA/BackupCodeGeneratorTest.php b/tests/Services/UserSystem/TFA/BackupCodeGeneratorTest.php similarity index 96% rename from tests/Services/TFA/BackupCodeGeneratorTest.php rename to tests/Services/UserSystem/TFA/BackupCodeGeneratorTest.php index 7adfe0d8..21e64c67 100644 --- a/tests/Services/TFA/BackupCodeGeneratorTest.php +++ b/tests/Services/UserSystem/TFA/BackupCodeGeneratorTest.php @@ -40,9 +40,9 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Tests\Services\TFA; +namespace App\Tests\Services\UserSystem\TFA; -use App\Services\TFA\BackupCodeGenerator; +use App\Services\UserSystem\TFA\BackupCodeGenerator; use PHPUnit\Framework\TestCase; use RuntimeException; diff --git a/tests/Services/TFA/BackupCodeManagerTest.php b/tests/Services/UserSystem/TFA/BackupCodeManagerTest.php similarity index 97% rename from tests/Services/TFA/BackupCodeManagerTest.php rename to tests/Services/UserSystem/TFA/BackupCodeManagerTest.php index a6b881d0..f39c805d 100644 --- a/tests/Services/TFA/BackupCodeManagerTest.php +++ b/tests/Services/UserSystem/TFA/BackupCodeManagerTest.php @@ -40,10 +40,10 @@ declare(strict_types=1); * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -namespace App\Tests\Services\TFA; +namespace App\Tests\Services\UserSystem\TFA; use App\Entity\UserSystem\User; -use App\Services\TFA\BackupCodeManager; +use App\Services\UserSystem\TFA\BackupCodeManager; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BackupCodeManagerTest extends WebTestCase diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index b4cb43d3..a3eba135 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -7,7 +7,7 @@ Part-DB1\templates\AdminPages\AttachmentTypeAdmin.html.twig:4 templates\AdminPages\AttachmentTypeAdmin.html.twig:4 - + attachment_type.caption File types for attachments @@ -17,7 +17,7 @@ Part-DB1\templates\AdminPages\AttachmentTypeAdmin.html.twig:12 new - + attachment_type.edit Edit file type @@ -27,7 +27,7 @@ Part-DB1\templates\AdminPages\AttachmentTypeAdmin.html.twig:16 new - + attachment_type.new New file type @@ -46,7 +46,7 @@ templates\base.html.twig:197 templates\base.html.twig:225 - + category.labelp Categories @@ -59,7 +59,7 @@ Part-DB1\templates\AdminPages\StorelocationAdmin.html.twig:11 templates\AdminPages\CategoryAdmin.html.twig:8 - + admin.options Options @@ -72,7 +72,7 @@ Part-DB1\templates\AdminPages\CompanyAdminBase.html.twig:15 templates\AdminPages\CategoryAdmin.html.twig:9 - + admin.advanced Advanced @@ -82,7 +82,7 @@ Part-DB1\templates\AdminPages\CategoryAdmin.html.twig:13 new - + category.edit Edit category @@ -92,7 +92,7 @@ Part-DB1\templates\AdminPages\CategoryAdmin.html.twig:17 new - + category.new New category @@ -102,7 +102,7 @@ Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:4 Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:4 - + currency.caption Currency @@ -112,7 +112,7 @@ Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:12 Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:12 - + currency.iso_code.caption ISO code @@ -122,7 +122,7 @@ Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:15 Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:15 - + currency.symbol.caption Currency symbol @@ -132,7 +132,7 @@ Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:29 new - + currency.edit Edit currency @@ -142,7 +142,7 @@ Part-DB1\templates\AdminPages\CurrencyAdmin.html.twig:33 new - + currency.new New currency @@ -153,7 +153,7 @@ Part-DB1\templates\AdminPages\DeviceAdmin.html.twig:4 templates\AdminPages\DeviceAdmin.html.twig:4 - + device.caption Device @@ -163,7 +163,7 @@ Part-DB1\templates\AdminPages\DeviceAdmin.html.twig:8 new - + device.edit Edit device @@ -173,7 +173,7 @@ Part-DB1\templates\AdminPages\DeviceAdmin.html.twig:12 new - + device.new New device @@ -196,7 +196,7 @@ templates\base.html.twig:206 templates\base.html.twig:237 - + search.placeholder Search @@ -212,7 +212,7 @@ templates\base.html.twig:193 templates\base.html.twig:221 - + expandAll Expand All @@ -228,7 +228,7 @@ templates\base.html.twig:194 templates\base.html.twig:222 - + reduceAll Reduce All @@ -240,9 +240,9 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:54 Part-DB1\templates\Parts\info\_sidebar.html.twig:4 - + part.info.timetravel_hint - This is how the part appeared before %timestamp%. <i>Please note that this feature is experimental, so the infos are maybe not correct.</i> + Please note that this feature is experimental, so the infos are maybe not correct.]]> @@ -251,7 +251,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:60 templates\AdminPages\EntityAdminBase.html.twig:42 - + standard.label Properties @@ -262,7 +262,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:61 templates\AdminPages\EntityAdminBase.html.twig:43 - + infos.label Infos @@ -273,7 +273,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:63 new - + history.label History @@ -284,7 +284,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:66 templates\AdminPages\EntityAdminBase.html.twig:45 - + export.label Export @@ -295,7 +295,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:68 templates\AdminPages\EntityAdminBase.html.twig:47 - + import_export.label Import / Export @@ -305,7 +305,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:69 Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:69 - + mass_creation.label Mass creation @@ -316,7 +316,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:82 templates\AdminPages\EntityAdminBase.html.twig:59 - + admin.common Common @@ -326,7 +326,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:86 Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:86 - + admin.attachments Attachments @@ -335,7 +335,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:90 - + admin.parameters Parameters @@ -346,7 +346,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:167 templates\AdminPages\EntityAdminBase.html.twig:142 - + export_all.label Export all elements @@ -356,7 +356,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:185 Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:173 - + mass_creation.help Each line will be interpreted as a name of a element, which will be created. @@ -367,7 +367,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:45 templates\AdminPages\EntityAdminBase.html.twig:35 - + edit.caption Edit element "%name" @@ -378,7 +378,7 @@ Part-DB1\templates\AdminPages\EntityAdminBase.html.twig:50 templates\AdminPages\EntityAdminBase.html.twig:37 - + new.caption New element @@ -393,7 +393,7 @@ templates\base.html.twig:199 templates\base.html.twig:227 - + footprint.labelp Footprints @@ -403,7 +403,7 @@ Part-DB1\templates\AdminPages\FootprintAdmin.html.twig:13 new - + footprint.edit Edit footprint @@ -413,7 +413,7 @@ Part-DB1\templates\AdminPages\FootprintAdmin.html.twig:17 new - + footprint.new New footprint @@ -423,7 +423,7 @@ Part-DB1\templates\AdminPages\GroupAdmin.html.twig:4 Part-DB1\templates\AdminPages\GroupAdmin.html.twig:4 - + group.edit.caption Groups @@ -435,7 +435,7 @@ Part-DB1\templates\AdminPages\GroupAdmin.html.twig:9 Part-DB1\templates\AdminPages\UserAdmin.html.twig:16 - + user.edit.permissions Permissions @@ -445,7 +445,7 @@ Part-DB1\templates\AdminPages\GroupAdmin.html.twig:24 new - + group.edit Edit group @@ -455,7 +455,7 @@ Part-DB1\templates\AdminPages\GroupAdmin.html.twig:28 new - + group.new New group @@ -464,7 +464,7 @@ Part-DB1\templates\AdminPages\LabelProfileAdmin.html.twig:4 - + label_profile.caption Label profiles @@ -473,7 +473,7 @@ Part-DB1\templates\AdminPages\LabelProfileAdmin.html.twig:8 - + label_profile.advanced Advanced @@ -482,7 +482,7 @@ Part-DB1\templates\AdminPages\LabelProfileAdmin.html.twig:9 - + label_profile.comment Comment @@ -492,7 +492,7 @@ Part-DB1\templates\AdminPages\LabelProfileAdmin.html.twig:55 new - + label_profile.edit Edit label profile @@ -502,7 +502,7 @@ Part-DB1\templates\AdminPages\LabelProfileAdmin.html.twig:59 new - + label_profile.new New label profile @@ -513,7 +513,7 @@ Part-DB1\templates\AdminPages\ManufacturerAdmin.html.twig:4 templates\AdminPages\ManufacturerAdmin.html.twig:4 - + manufacturer.caption Manufacturers @@ -523,7 +523,7 @@ Part-DB1\templates\AdminPages\ManufacturerAdmin.html.twig:8 new - + manufacturer.edit Edit manufacturer @@ -533,7 +533,7 @@ Part-DB1\templates\AdminPages\ManufacturerAdmin.html.twig:12 new - + manufacturer.new New manufacturer @@ -543,7 +543,7 @@ Part-DB1\templates\AdminPages\MeasurementUnitAdmin.html.twig:4 Part-DB1\templates\AdminPages\MeasurementUnitAdmin.html.twig:4 - + measurement_unit.caption Measurement Unit @@ -558,7 +558,7 @@ templates\base.html.twig:198 templates\base.html.twig:226 - + storelocation.labelp Storelocations @@ -568,7 +568,7 @@ Part-DB1\templates\AdminPages\StorelocationAdmin.html.twig:32 new - + storelocation.edit Edit store location @@ -578,7 +578,7 @@ Part-DB1\templates\AdminPages\StorelocationAdmin.html.twig:36 new - + storelocation.new New store location @@ -589,7 +589,7 @@ Part-DB1\templates\AdminPages\SupplierAdmin.html.twig:4 templates\AdminPages\SupplierAdmin.html.twig:4 - + supplier.caption Suppliers @@ -599,7 +599,7 @@ Part-DB1\templates\AdminPages\SupplierAdmin.html.twig:16 new - + supplier.edit Edit supplier @@ -609,7 +609,7 @@ Part-DB1\templates\AdminPages\SupplierAdmin.html.twig:20 new - + supplier.new New supplier @@ -619,7 +619,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:8 Part-DB1\templates\AdminPages\UserAdmin.html.twig:8 - + user.edit.caption Users @@ -629,7 +629,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:14 Part-DB1\templates\AdminPages\UserAdmin.html.twig:14 - + user.edit.configuration Configuration @@ -639,7 +639,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:15 Part-DB1\templates\AdminPages\UserAdmin.html.twig:15 - + user.edit.password Password @@ -649,7 +649,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:45 Part-DB1\templates\AdminPages\UserAdmin.html.twig:45 - + user.edit.tfa.caption Two-factor authentication @@ -659,7 +659,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:47 Part-DB1\templates\AdminPages\UserAdmin.html.twig:47 - + user.edit.tfa.google_active Authenticator app active @@ -673,7 +673,7 @@ Part-DB1\templates\Users\backup_codes.html.twig:15 Part-DB1\templates\Users\_2fa_settings.html.twig:95 - + tfa_backup.remaining_tokens Remaining backup codes count @@ -687,7 +687,7 @@ Part-DB1\templates\Users\backup_codes.html.twig:17 Part-DB1\templates\Users\_2fa_settings.html.twig:96 - + tfa_backup.generation_date Generation date of the backup codes @@ -699,7 +699,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:53 Part-DB1\templates\AdminPages\UserAdmin.html.twig:60 - + user.edit.tfa.disabled Method not enabled @@ -709,7 +709,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:56 Part-DB1\templates\AdminPages\UserAdmin.html.twig:56 - + user.edit.tfa.u2f_keys_count Active security keys @@ -719,7 +719,7 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:72 Part-DB1\templates\AdminPages\UserAdmin.html.twig:72 - + user.edit.tfa.disable_tfa_title Do you really want to proceed? @@ -729,12 +729,12 @@ Part-DB1\templates\AdminPages\UserAdmin.html.twig:72 Part-DB1\templates\AdminPages\UserAdmin.html.twig:72 - + user.edit.tfa.disable_tfa_message - This will disable <b>all active two-factor authentication methods of the user</b> and delete the <b>backup codes</b>! -<br> -The user will have to set up all two-factor authentication methods again and print new backup codes! <br><br> -<b>Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!</b> + all active two-factor authentication methods of the user and delete the backup codes! +
    +The user will have to set up all two-factor authentication methods again and print new backup codes!

    +Only do this if you are absolutely sure about the identity of the user (seeking help), otherwise the account could be compromised by an attacker!]]>
    @@ -742,7 +742,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\UserAdmin.html.twig:73 Part-DB1\templates\AdminPages\UserAdmin.html.twig:73 - + user.edit.tfa.disable_tfa.btn Disable all two-factor authentication methods @@ -752,7 +752,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\UserAdmin.html.twig:85 new - + user.edit Edit user @@ -762,7 +762,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\UserAdmin.html.twig:89 new - + user.new New user @@ -775,7 +775,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\edit\_attachments.html.twig:4 Part-DB1\templates\Parts\info\_attachments_info.html.twig:63 - + attachment.delete Delete @@ -789,7 +789,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\edit\_attachments.html.twig:38 Part-DB1\src\DataTables\AttachmentDataTable.php:159 - + attachment.external External @@ -801,7 +801,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\_attachments.html.twig:47 Part-DB1\templates\Parts\edit\_attachments.html.twig:45 - + attachment.preview.alt Attachment thumbnail @@ -815,7 +815,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\edit\_attachments.html.twig:48 Part-DB1\templates\Parts\info\_attachments_info.html.twig:45 - + attachment.view View @@ -831,7 +831,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\info\_attachments_info.html.twig:38 Part-DB1\src\DataTables\AttachmentDataTable.php:166 - + attachment.file_not_found File not found @@ -843,7 +843,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\info\_attachments_info.html.twig:48 Part-DB1\templates\Parts\edit\_attachments.html.twig:62 - + attachment.secure Private attachment @@ -855,7 +855,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\_attachments.html.twig:77 Part-DB1\templates\Parts\edit\_attachments.html.twig:75 - + attachment.create Add attachment @@ -869,7 +869,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\Parts\edit\_attachments.html.twig:80 Part-DB1\templates\Parts\edit\_lots.html.twig:33 - + part_lot.edit.delete.confirm Do you really want to delete this stock? This can not be undone! @@ -880,7 +880,7 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\_delete_form.html.twig:2 templates\AdminPages\_delete_form.html.twig:2 - + entity.delete.confirm_title You really want to delete %name%? @@ -891,11 +891,11 @@ The user will have to set up all two-factor authentication methods again and pri Part-DB1\templates\AdminPages\_delete_form.html.twig:3 templates\AdminPages\_delete_form.html.twig:3 - + entity.delete.message - This can not be undone! -<br> -Sub elements will be moved upwards. + +Sub elements will be moved upwards.]]> @@ -904,7 +904,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_delete_form.html.twig:11 templates\AdminPages\_delete_form.html.twig:9 - + entity.delete Delete element @@ -919,7 +919,7 @@ Sub elements will be moved upwards. Part-DB1\src\Form\Part\PartBaseType.php:267 new - + edit.log_comment Change comment @@ -930,7 +930,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_delete_form.html.twig:24 templates\AdminPages\_delete_form.html.twig:12 - + entity.delete.recursive Delete recursive (all sub elements) @@ -939,7 +939,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_duplicate.html.twig:3 - + entity.duplicate Duplicate element @@ -953,7 +953,7 @@ Sub elements will be moved upwards. templates\AdminPages\_export_form.html.twig:4 src\Form\ImportType.php:67 - + export.format File format @@ -964,7 +964,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:16 templates\AdminPages\_export_form.html.twig:16 - + export.level Verbosity level @@ -975,7 +975,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:19 templates\AdminPages\_export_form.html.twig:19 - + export.level.simple Simple @@ -986,7 +986,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:20 templates\AdminPages\_export_form.html.twig:20 - + export.level.extended Extended @@ -997,7 +997,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:21 templates\AdminPages\_export_form.html.twig:21 - + export.level.full Full @@ -1008,7 +1008,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:31 templates\AdminPages\_export_form.html.twig:31 - + export.include_children Include children elements in export @@ -1019,7 +1019,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_export_form.html.twig:39 templates\AdminPages\_export_form.html.twig:39 - + export.btn Export @@ -1038,7 +1038,7 @@ Sub elements will be moved upwards. templates\Parts\edit_part_info.html.twig:12 templates\Parts\show_part_info.html.twig:11 - + id.label ID @@ -1062,7 +1062,7 @@ Sub elements will be moved upwards. templates\AdminPages\EntityAdminBase.html.twig:101 templates\Parts\show_part_info.html.twig:248 - + createdAt Created At @@ -1080,7 +1080,7 @@ Sub elements will be moved upwards. templates\AdminPages\EntityAdminBase.html.twig:114 templates\Parts\show_part_info.html.twig:263 - + lastModified Last modified @@ -1090,7 +1090,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_info.html.twig:38 Part-DB1\templates\AdminPages\_info.html.twig:38 - + entity.info.parts_count Number of parts with this element @@ -1101,7 +1101,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:125 Part-DB1\templates\Parts\edit\_specifications.html.twig:6 - + specifications.property Parameter @@ -1111,7 +1111,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:7 Part-DB1\templates\Parts\edit\_specifications.html.twig:7 - + specifications.symbol Symbol @@ -1121,7 +1121,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:8 Part-DB1\templates\Parts\edit\_specifications.html.twig:8 - + specifications.value_min Min. @@ -1131,7 +1131,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:9 Part-DB1\templates\Parts\edit\_specifications.html.twig:9 - + specifications.value_typ Typ. @@ -1141,7 +1141,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:10 Part-DB1\templates\Parts\edit\_specifications.html.twig:10 - + specifications.value_max Max. @@ -1151,7 +1151,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:11 Part-DB1\templates\Parts\edit\_specifications.html.twig:11 - + specifications.unit Unit @@ -1161,7 +1161,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:12 Part-DB1\templates\Parts\edit\_specifications.html.twig:12 - + specifications.text Text @@ -1171,7 +1171,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:13 Part-DB1\templates\Parts\edit\_specifications.html.twig:13 - + specifications.group Group @@ -1181,7 +1181,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:26 Part-DB1\templates\Parts\edit\_specifications.html.twig:26 - + specification.create New Parameter @@ -1191,7 +1191,7 @@ Sub elements will be moved upwards. Part-DB1\templates\AdminPages\_parameters.html.twig:31 Part-DB1\templates\Parts\edit\_specifications.html.twig:31 - + parameter.delete.confirm Do you really want to delete this parameter? @@ -1201,7 +1201,7 @@ Sub elements will be moved upwards. Part-DB1\templates\attachment_list.html.twig:3 Part-DB1\templates\attachment_list.html.twig:3 - + attachment.list.title Attachments list @@ -1215,7 +1215,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LogSystem\_log_table.html.twig:8 Part-DB1\templates\Parts\lists\_parts_list.html.twig:6 - + part_list.loading.caption Loading @@ -1229,7 +1229,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LogSystem\_log_table.html.twig:9 Part-DB1\templates\Parts\lists\_parts_list.html.twig:7 - + part_list.loading.message This can take a moment. If this message do not disappear, try to reload the page. @@ -1240,7 +1240,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:68 templates\base.html.twig:246 - + vendor.base.javascript_hint Please activate Javascript to use all features! @@ -1250,7 +1250,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:73 Part-DB1\templates\base.html.twig:73 - + sidebar.big.toggle Show/Hide sidebar @@ -1261,7 +1261,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:95 templates\base.html.twig:271 - + loading.caption Loading: @@ -1272,7 +1272,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:96 templates\base.html.twig:272 - + loading.message This can take a while. If this messages stays for a long time, try to reload the page. @@ -1283,7 +1283,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:101 templates\base.html.twig:277 - + loading.bar Loading... @@ -1294,7 +1294,7 @@ Sub elements will be moved upwards. Part-DB1\templates\base.html.twig:112 templates\base.html.twig:288 - + back_to_top Back to page's top @@ -1304,7 +1304,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:35 Part-DB1\templates\Form\permissionLayout.html.twig:35 - + permission.edit.permission Permissions @@ -1314,7 +1314,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:36 Part-DB1\templates\Form\permissionLayout.html.twig:36 - + permission.edit.value Value @@ -1324,7 +1324,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:53 Part-DB1\templates\Form\permissionLayout.html.twig:53 - + permission.legend.title Explanation of the states: @@ -1334,7 +1334,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:57 Part-DB1\templates\Form\permissionLayout.html.twig:57 - + permission.legend.disallow Forbidden @@ -1344,7 +1344,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:61 Part-DB1\templates\Form\permissionLayout.html.twig:61 - + permission.legend.allow Allowed @@ -1354,7 +1354,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Form\permissionLayout.html.twig:65 Part-DB1\templates\Form\permissionLayout.html.twig:65 - + permission.legend.inherit Inherit from (parent) group @@ -1364,7 +1364,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:3 Part-DB1\templates\helper.twig:3 - + bool.true True @@ -1374,7 +1374,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:5 Part-DB1\templates\helper.twig:5 - + bool.false False @@ -1384,7 +1384,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:92 Part-DB1\templates\helper.twig:87 - + Yes Yes @@ -1394,7 +1394,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:94 Part-DB1\templates\helper.twig:89 - + No No @@ -1403,7 +1403,7 @@ Sub elements will be moved upwards. Part-DB1\templates\helper.twig:126 - + specifications.value Value @@ -1414,7 +1414,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:7 templates\homepage.html.twig:7 - + version.caption Version @@ -1425,7 +1425,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:22 templates\homepage.html.twig:19 - + homepage.license License information @@ -1436,7 +1436,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:31 templates\homepage.html.twig:28 - + homepage.github.caption Project page @@ -1447,9 +1447,9 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:31 templates\homepage.html.twig:28 - + homepage.github.text - Source, downloads, bug reports, to-do-list etc. can be found on <a href="%href%" class="link-external" target="_blank">GitHub project page</a> + GitHub project page]]> @@ -1458,7 +1458,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:32 templates\homepage.html.twig:29 - + homepage.help.caption Help @@ -1469,9 +1469,9 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:32 templates\homepage.html.twig:29 - + homepage.help.text - Help and tips can be found in Wiki the <a href="%href%" class="link-external" target="_blank">GitHub page</a> + GitHub page]]> @@ -1480,7 +1480,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:33 templates\homepage.html.twig:30 - + homepage.forum.caption Forum @@ -1491,9 +1491,9 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:33 templates\homepage.html.twig:30 - + homepage.forum.text - For questions about the Part-DB there is a thread on <a href="%href%" class="link-external" target="_blank">mikrocontroller.net</a> + mikrocontroller.net]]> @@ -1502,7 +1502,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:34 templates\homepage.html.twig:31 - + homepage.wiki.caption Wiki @@ -1513,9 +1513,9 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:34 templates\homepage.html.twig:31 - + homepage.wiki.text - Further information is available in <a href="%href%" class="link-external" target="_blank">mikrocontroller.net Article</a> + mikrocontroller.net Article]]> @@ -1524,7 +1524,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:36 templates\homepage.html.twig:33 - + homepage.basedOn Based on the original Part-DB by @@ -1535,7 +1535,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:39 templates\homepage.html.twig:36 - + homepage.others and others @@ -1546,7 +1546,7 @@ Sub elements will be moved upwards. Part-DB1\templates\homepage.html.twig:45 new - + homepage.last_activity Last activity @@ -1556,7 +1556,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:3 Part-DB1\templates\LabelSystem\dialog.html.twig:6 - + label_generator.title Label generator @@ -1565,7 +1565,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:16 - + label_generator.common Common @@ -1574,7 +1574,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:20 - + label_generator.advanced Advanced @@ -1583,7 +1583,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:24 - + label_generator.profiles Profiles @@ -1592,7 +1592,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:58 - + label_generator.selected_profile Currently selected profile @@ -1601,7 +1601,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:62 - + label_generator.edit_profile Edit profile @@ -1610,7 +1610,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:75 - + label_generator.load_profile Load profile @@ -1619,7 +1619,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dialog.html.twig:102 - + label_generator.download Download @@ -1629,7 +1629,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dropdown_macro.html.twig:3 Part-DB1\templates\LabelSystem\dropdown_macro.html.twig:5 - + label_generator.label_btn Generate label @@ -1638,7 +1638,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\dropdown_macro.html.twig:20 - + label_generator.label_empty New empty label @@ -1647,7 +1647,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\Scanner\dialog.html.twig:3 - + label_scanner.title Label scanner @@ -1656,7 +1656,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\Scanner\dialog.html.twig:7 - + label_scanner.no_cam_found.title No webcam found @@ -1665,7 +1665,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\Scanner\dialog.html.twig:7 - + label_scanner.no_cam_found.text You need a webcam and give permission to use the scanner function. You can input the barcode code manually below. @@ -1674,7 +1674,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LabelSystem\Scanner\dialog.html.twig:27 - + label_scanner.source_select Select source @@ -1684,7 +1684,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LogSystem\log_list.html.twig:3 Part-DB1\templates\LogSystem\log_list.html.twig:3 - + log.list.title System log @@ -1695,7 +1695,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LogSystem\_log_table.html.twig:1 new - + log.undo.confirm_title Really undo change / revert to timestamp? @@ -1706,7 +1706,7 @@ Sub elements will be moved upwards. Part-DB1\templates\LogSystem\_log_table.html.twig:2 new - + log.undo.confirm_message Do you really want to undo the given change / reset the element to the given timestamp? @@ -1716,7 +1716,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\base.html.twig:24 Part-DB1\templates\mail\base.html.twig:24 - + mail.footer.email_sent_by This email was sent automatically by @@ -1726,7 +1726,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\base.html.twig:24 Part-DB1\templates\mail\base.html.twig:24 - + mail.footer.dont_reply Do not answer to this email. @@ -1736,7 +1736,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:6 Part-DB1\templates\mail\pw_reset.html.twig:6 - + email.hi %name% Hi %name% @@ -1746,7 +1746,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:7 Part-DB1\templates\mail\pw_reset.html.twig:7 - + email.pw_reset.message somebody (hopefully you) requested a reset of your password. If this request was not made by you, ignore this mail. @@ -1756,7 +1756,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:9 Part-DB1\templates\mail\pw_reset.html.twig:9 - + email.pw_reset.button Click here to reset password @@ -1766,9 +1766,9 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:11 Part-DB1\templates\mail\pw_reset.html.twig:11 - + email.pw_reset.fallback - If this does not work for you, go to <a href="%url%">%url%</a> and enter the following info + %url% and enter the following info]]> @@ -1776,7 +1776,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:16 Part-DB1\templates\mail\pw_reset.html.twig:16 - + email.pw_reset.username Username @@ -1786,7 +1786,7 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:19 Part-DB1\templates\mail\pw_reset.html.twig:19 - + email.pw_reset.token Token @@ -1796,9 +1796,9 @@ Sub elements will be moved upwards. Part-DB1\templates\mail\pw_reset.html.twig:24 Part-DB1\templates\mail\pw_reset.html.twig:24 - + email.pw_reset.valid_unit %date% - The reset token will be valid until <i>%date%</i>. + %date%.]]> @@ -1808,7 +1808,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:78 Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:58 - + orderdetail.delete Delete @@ -1818,7 +1818,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:39 Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:39 - + pricedetails.edit.min_qty Minimum discount quantity @@ -1828,7 +1828,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:40 Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:40 - + pricedetails.edit.price Price @@ -1838,7 +1838,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:41 Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:41 - + pricedetails.edit.price_qty for amount @@ -1848,7 +1848,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:54 Part-DB1\templates\Parts\edit\edit_form_styles.html.twig:54 - + pricedetail.create Add price @@ -1859,7 +1859,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:4 templates\Parts\edit_part_info.html.twig:4 - + part.edit.title Edit part @@ -1870,7 +1870,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:9 templates\Parts\edit_part_info.html.twig:9 - + part.edit.card_title Edit part @@ -1880,7 +1880,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:22 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:22 - + part.edit.tab.common Common @@ -1890,7 +1890,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:28 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:28 - + part.edit.tab.manufacturer Manufacturer @@ -1900,7 +1900,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:34 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:34 - + part.edit.tab.advanced Advanced @@ -1910,7 +1910,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:40 - + part.edit.tab.part_lots Stocks @@ -1920,7 +1920,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:46 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:46 - + part.edit.tab.attachments Attachments @@ -1930,7 +1930,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:52 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:52 - + part.edit.tab.orderdetails Purchase informations @@ -1939,7 +1939,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:58 - + part.edit.tab.specifications Parameters @@ -1949,7 +1949,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\edit_part_info.html.twig:64 Part-DB1\templates\Parts\edit\edit_part_info.html.twig:58 - + part.edit.tab.comment Comment @@ -1960,7 +1960,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\new_part.html.twig:8 templates\Parts\new_part.html.twig:8 - + part.new.card_title Create new part @@ -1970,7 +1970,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\_lots.html.twig:5 Part-DB1\templates\Parts\edit\_lots.html.twig:5 - + part_lot.delete Delete @@ -1980,7 +1980,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\_lots.html.twig:28 Part-DB1\templates\Parts\edit\_lots.html.twig:28 - + part_lot.create Add stock @@ -1990,7 +1990,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\_orderdetails.html.twig:13 Part-DB1\templates\Parts\edit\_orderdetails.html.twig:13 - + orderdetail.create Add distributor @@ -2000,7 +2000,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\_orderdetails.html.twig:18 Part-DB1\templates\Parts\edit\_orderdetails.html.twig:18 - + pricedetails.edit.delete.confirm Do you really want to delete this price? This can not be undone. @@ -2010,7 +2010,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\edit\_orderdetails.html.twig:62 Part-DB1\templates\Parts\edit\_orderdetails.html.twig:61 - + orderdetails.edit.delete.confirm Do you really want to delete this distributor info? This can not be undone! @@ -2024,7 +2024,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:4 templates\Parts\show_part_info.html.twig:9 - + part.info.title Detail info for part @@ -2034,7 +2034,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:47 Part-DB1\templates\Parts\info\show_part_info.html.twig:47 - + part.part_lots.label Stocks @@ -2049,7 +2049,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:74 src\Form\PartType.php:86 - + comment.label Comment @@ -2058,7 +2058,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:64 - + part.info.specifications Parameters @@ -2069,7 +2069,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:64 templates\Parts\show_part_info.html.twig:82 - + attachment.labelp Attachments @@ -2080,7 +2080,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:71 templates\Parts\show_part_info.html.twig:88 - + vendor.partinfo.shopping_infos Shopping informations @@ -2091,7 +2091,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:78 templates\Parts\show_part_info.html.twig:94 - + vendor.partinfo.history History @@ -2110,7 +2110,7 @@ Sub elements will be moved upwards. templates\base.html.twig:231 templates\Parts\show_part_info.html.twig:100 - + tools.label Tools @@ -2120,7 +2120,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\show_part_info.html.twig:103 Part-DB1\templates\Parts\info\show_part_info.html.twig:90 - + extended_info.label Extended infos @@ -2130,7 +2130,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:7 Part-DB1\templates\Parts\info\_attachments_info.html.twig:7 - + attachment.name Name @@ -2140,7 +2140,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:8 Part-DB1\templates\Parts\info\_attachments_info.html.twig:8 - + attachment.attachment_type Attachment Type @@ -2150,7 +2150,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:9 Part-DB1\templates\Parts\info\_attachments_info.html.twig:9 - + attachment.file_name File name @@ -2160,7 +2160,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:10 Part-DB1\templates\Parts\info\_attachments_info.html.twig:10 - + attachment.file_size File size @@ -2169,7 +2169,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:54 - + attachment.preview Preview picture @@ -2179,7 +2179,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_attachments_info.html.twig:67 Part-DB1\templates\Parts\info\_attachments_info.html.twig:50 - + attachment.download Download @@ -2190,7 +2190,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:11 new - + user.creating_user User who created this part @@ -2204,7 +2204,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:28 Part-DB1\templates\Parts\info\_extended_infos.html.twig:50 - + Unknown Unknown @@ -2217,7 +2217,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:30 new - + accessDenied Access Denied @@ -2228,7 +2228,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:26 new - + user.last_editing_user User who edited this part last @@ -2238,7 +2238,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:41 Part-DB1\templates\Parts\info\_extended_infos.html.twig:41 - + part.isFavorite Favorite @@ -2248,7 +2248,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_extended_infos.html.twig:46 Part-DB1\templates\Parts\info\_extended_infos.html.twig:46 - + part.minOrderAmount Minimum order amount @@ -2265,7 +2265,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:24 src\Form\PartType.php:80 - + manufacturer.label Manufacturer @@ -2277,7 +2277,7 @@ Sub elements will be moved upwards. templates\base.html.twig:54 src\Form\PartType.php:62 - + name.label Name @@ -2288,7 +2288,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_main_infos.html.twig:27 new - + part.back_to_info Back to current version @@ -2303,7 +2303,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:31 src\Form\PartType.php:65 - + description.label Description @@ -2320,7 +2320,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:32 src\Form\PartType.php:74 - + category.label Category @@ -2332,7 +2332,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:42 src\Form\PartType.php:69 - + instock.label Instock @@ -2344,7 +2344,7 @@ Sub elements will be moved upwards. templates\Parts\show_part_info.html.twig:44 src\Form\PartType.php:72 - + mininstock.label Minimum Instock @@ -2360,7 +2360,7 @@ Sub elements will be moved upwards. templates\base.html.twig:73 templates\Parts\show_part_info.html.twig:47 - + footprint.label Footprint @@ -2373,7 +2373,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_main_infos.html.twig:60 templates\Parts\show_part_info.html.twig:51 - + part.avg_price.label Average Price @@ -2383,7 +2383,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:5 Part-DB1\templates\Parts\info\_order_infos.html.twig:5 - + part.supplier.name Name @@ -2393,7 +2393,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:6 Part-DB1\templates\Parts\info\_order_infos.html.twig:6 - + part.supplier.partnr Partnr. @@ -2403,7 +2403,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:28 Part-DB1\templates\Parts\info\_order_infos.html.twig:28 - + part.order.minamount Minimum amount @@ -2413,7 +2413,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:29 Part-DB1\templates\Parts\info\_order_infos.html.twig:29 - + part.order.price Price @@ -2423,7 +2423,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:31 Part-DB1\templates\Parts\info\_order_infos.html.twig:31 - + part.order.single_price Unit Price @@ -2433,7 +2433,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:71 Part-DB1\templates\Parts\info\_order_infos.html.twig:71 - + edit.caption_short Edit @@ -2443,7 +2443,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_order_infos.html.twig:72 Part-DB1\templates\Parts\info\_order_infos.html.twig:72 - + delete.caption Delete @@ -2453,7 +2453,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:7 Part-DB1\templates\Parts\info\_part_lots.html.twig:6 - + part_lots.description Description @@ -2463,7 +2463,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:8 Part-DB1\templates\Parts\info\_part_lots.html.twig:7 - + part_lots.storage_location Storage location @@ -2473,7 +2473,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:9 Part-DB1\templates\Parts\info\_part_lots.html.twig:8 - + part_lots.amount Amount @@ -2483,7 +2483,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:24 Part-DB1\templates\Parts\info\_part_lots.html.twig:22 - + part_lots.location_unknown Storage location unknown @@ -2493,7 +2493,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:31 Part-DB1\templates\Parts\info\_part_lots.html.twig:29 - + part_lots.instock_unknown Amount unknown @@ -2503,7 +2503,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:40 Part-DB1\templates\Parts\info\_part_lots.html.twig:38 - + part_lots.expiration_date Expiration date @@ -2513,7 +2513,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:48 Part-DB1\templates\Parts\info\_part_lots.html.twig:46 - + part_lots.is_expired Expired @@ -2523,7 +2523,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_part_lots.html.twig:55 Part-DB1\templates\Parts\info\_part_lots.html.twig:53 - + part_lots.need_refill Needs refill @@ -2533,7 +2533,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_picture.html.twig:15 Part-DB1\templates\Parts\info\_picture.html.twig:15 - + part.info.prev_picture Previous picture @@ -2543,7 +2543,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_picture.html.twig:19 Part-DB1\templates\Parts\info\_picture.html.twig:19 - + part.info.next_picture Next picture @@ -2553,7 +2553,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_sidebar.html.twig:21 Part-DB1\templates\Parts\info\_sidebar.html.twig:21 - + part.mass.tooltip Mass @@ -2563,7 +2563,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_sidebar.html.twig:30 Part-DB1\templates\Parts\info\_sidebar.html.twig:30 - + part.needs_review.badge Needs review @@ -2573,7 +2573,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_sidebar.html.twig:39 Part-DB1\templates\Parts\info\_sidebar.html.twig:39 - + part.favorite.badge Favorite @@ -2583,7 +2583,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_sidebar.html.twig:47 Part-DB1\templates\Parts\info\_sidebar.html.twig:47 - + part.obsolete.badge No longer available @@ -2592,7 +2592,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_specifications.html.twig:10 - + parameters.extracted_from_description Automatically extracted from description @@ -2601,7 +2601,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_specifications.html.twig:15 - + parameters.auto_extracted_from_comment Automatically extracted from comment @@ -2612,7 +2612,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_tools.html.twig:4 templates\Parts\show_part_info.html.twig:125 - + part.edit.btn Edit part @@ -2623,7 +2623,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_tools.html.twig:14 templates\Parts\show_part_info.html.twig:135 - + part.clone.btn Clone part @@ -2634,7 +2634,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_action_bar.html.twig:4 templates\Parts\show_part_info.html.twig:143 - + part.create.btn Create new part @@ -2644,7 +2644,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_tools.html.twig:31 Part-DB1\templates\Parts\info\_tools.html.twig:29 - + part.delete.confirm_title Do you really want to delete this part? @@ -2654,7 +2654,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_tools.html.twig:32 Part-DB1\templates\Parts\info\_tools.html.twig:30 - + part.delete.message This part and any associated information (like attachments, price informations, etc.) will be deleted. This can not be undone! @@ -2664,7 +2664,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\info\_tools.html.twig:39 Part-DB1\templates\Parts\info\_tools.html.twig:37 - + part.delete Delete part @@ -2674,7 +2674,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\all_list.html.twig:4 Part-DB1\templates\Parts\lists\all_list.html.twig:4 - + parts_list.all.title All parts @@ -2684,7 +2684,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\category_list.html.twig:4 Part-DB1\templates\Parts\lists\category_list.html.twig:4 - + parts_list.category.title Parts with category @@ -2694,7 +2694,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\footprint_list.html.twig:4 Part-DB1\templates\Parts\lists\footprint_list.html.twig:4 - + parts_list.footprint.title Parts with footprint @@ -2704,7 +2704,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\manufacturer_list.html.twig:4 Part-DB1\templates\Parts\lists\manufacturer_list.html.twig:4 - + parts_list.manufacturer.title Parts with manufacturer @@ -2714,7 +2714,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\search_list.html.twig:4 Part-DB1\templates\Parts\lists\search_list.html.twig:4 - + parts_list.search.title Search Parts @@ -2724,7 +2724,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\store_location_list.html.twig:4 Part-DB1\templates\Parts\lists\store_location_list.html.twig:4 - + parts_list.storelocation.title Parts with store locations @@ -2734,7 +2734,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\supplier_list.html.twig:4 Part-DB1\templates\Parts\lists\supplier_list.html.twig:4 - + parts_list.supplier.title Parts with supplier @@ -2744,7 +2744,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\tags_list.html.twig:4 Part-DB1\templates\Parts\lists\tags_list.html.twig:4 - + parts_list.tags.title Parts with tag @@ -2754,7 +2754,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:22 Part-DB1\templates\Parts\lists\_info_card.html.twig:17 - + entity.info.common.tab Common @@ -2764,7 +2764,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:26 Part-DB1\templates\Parts\lists\_info_card.html.twig:20 - + entity.info.statistics.tab Statistics @@ -2773,7 +2773,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:31 - + entity.info.attachments.tab Attachments @@ -2782,7 +2782,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:37 - + entity.info.parameters.tab Parameters @@ -2792,7 +2792,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:54 Part-DB1\templates\Parts\lists\_info_card.html.twig:30 - + entity.info.name Name @@ -2804,7 +2804,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:34 Part-DB1\templates\Parts\lists\_info_card.html.twig:67 - + entity.info.parent Parent @@ -2814,7 +2814,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:70 Part-DB1\templates\Parts\lists\_info_card.html.twig:46 - + entity.edit.btn Edit @@ -2824,7 +2824,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Parts\lists\_info_card.html.twig:92 Part-DB1\templates\Parts\lists\_info_card.html.twig:63 - + entity.info.children_count Count of children elements @@ -2836,7 +2836,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\2fa_base_form.html.twig:3 Part-DB1\templates\security\2fa_base_form.html.twig:5 - + tfa.check.title Two-factor authentication needed @@ -2846,7 +2846,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\2fa_base_form.html.twig:39 Part-DB1\templates\security\2fa_base_form.html.twig:39 - + tfa.code.trusted_pc This is a trusted computer (if this is enabled, no further two-factor queries are performed on this computer) @@ -2858,7 +2858,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\2fa_base_form.html.twig:52 Part-DB1\templates\security\login.html.twig:58 - + login.btn Login @@ -2872,7 +2872,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_login.html.twig:13 Part-DB1\templates\_navbar.html.twig:40 - + user.logout Logout @@ -2882,7 +2882,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\2fa_form.html.twig:6 Part-DB1\templates\security\2fa_form.html.twig:6 - + tfa.check.code.label Authenticator app code @@ -2892,7 +2892,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\2fa_form.html.twig:10 Part-DB1\templates\security\2fa_form.html.twig:10 - + tfa.check.code.help Enter the 6-digit code from your Authenticator App or one of your backup codes if the Authenticator is not available. @@ -2903,7 +2903,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:3 templates\security\login.html.twig:3 - + login.title Login @@ -2914,7 +2914,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:7 templates\security\login.html.twig:7 - + login.card_title Login @@ -2925,7 +2925,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:31 templates\security\login.html.twig:31 - + login.username.label Username @@ -2936,7 +2936,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:34 templates\security\login.html.twig:34 - + login.username.placeholder Username @@ -2947,7 +2947,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:38 templates\security\login.html.twig:38 - + login.password.label Password @@ -2958,7 +2958,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:40 templates\security\login.html.twig:40 - + login.password.placeholder Password @@ -2969,7 +2969,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:50 templates\security\login.html.twig:50 - + login.rememberme Remember me (should not be used on shared computers) @@ -2979,7 +2979,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\login.html.twig:64 Part-DB1\templates\security\login.html.twig:64 - + pw_reset.password_forget Forgot username/password? @@ -2989,7 +2989,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\pw_reset_new_pw.html.twig:5 Part-DB1\templates\security\pw_reset_new_pw.html.twig:5 - + pw_reset.new_pw.header.title Set new password @@ -2999,7 +2999,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\pw_reset_request.html.twig:5 Part-DB1\templates\security\pw_reset_request.html.twig:5 - + pw_reset.request.header.title Request a new password @@ -3011,7 +3011,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_login.html.twig:7 Part-DB1\templates\security\U2F\u2f_register.html.twig:10 - + tfa_u2f.http_warning You are accessing this page using the insecure HTTP method, so U2F will most likely not work (Bad Request error message). Ask an administrator to set up the secure HTTPS method if you want to use security keys. @@ -3023,7 +3023,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_login.html.twig:10 Part-DB1\templates\security\U2F\u2f_register.html.twig:22 - + r_u2f_two_factor.pressbutton Please plug in your security key and press its button! @@ -3033,7 +3033,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:3 Part-DB1\templates\security\U2F\u2f_register.html.twig:3 - + tfa_u2f.add_key.title Add security key @@ -3045,7 +3045,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:6 Part-DB1\templates\Users\_2fa_settings.html.twig:111 - + tfa_u2f.explanation With the help of a U2F/FIDO compatible security key (e.g. YubiKey or NitroKey), user-friendly and secure two-factor authentication can be achieved. The security keys can be registered here, and if two-factor verification is required, the key only needs to be inserted via USB or typed against the device via NFC. @@ -3055,7 +3055,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:7 Part-DB1\templates\security\U2F\u2f_register.html.twig:7 - + tfa_u2f.add_key.backup_hint To ensure access even if the key is lost, it is recommended to register a second key as backup and store it in a safe place! @@ -3065,7 +3065,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:16 Part-DB1\templates\security\U2F\u2f_register.html.twig:16 - + r_u2f_two_factor.name Shown key name (e.g. Backup) @@ -3075,7 +3075,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:19 Part-DB1\templates\security\U2F\u2f_register.html.twig:19 - + tfa_u2f.add_key.add_button Add security key @@ -3085,7 +3085,7 @@ Sub elements will be moved upwards. Part-DB1\templates\security\U2F\u2f_register.html.twig:27 Part-DB1\templates\security\U2F\u2f_register.html.twig:27 - + tfa_u2f.add_key.back_to_settings Back to settings @@ -3098,7 +3098,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:8 new - + statistics.title Statistics @@ -3109,7 +3109,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:14 new - + statistics.parts Parts @@ -3120,7 +3120,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:19 new - + statistics.data_structures Data structures @@ -3131,7 +3131,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:24 new - + statistics.attachments Attachments @@ -3146,7 +3146,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:104 new - + statistics.property Property @@ -3161,7 +3161,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:105 new - + statistics.value Value @@ -3172,7 +3172,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:40 new - + statistics.distinct_parts_count Number of distinct parts @@ -3183,7 +3183,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:44 new - + statistics.parts_instock_sum Sum of all part instocks @@ -3194,7 +3194,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:48 new - + statistics.parts_with_price Number of parts with price information @@ -3205,7 +3205,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:65 new - + statistics.categories_count Number of categories @@ -3216,7 +3216,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:69 new - + statistics.footprints_count Number of footprints @@ -3227,7 +3227,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:73 new - + statistics.manufacturers_count Number of manufacturers @@ -3238,7 +3238,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:77 new - + statistics.storelocations_count Number of storelocations @@ -3249,7 +3249,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:81 new - + statistics.suppliers_count Number of suppliers @@ -3260,7 +3260,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:85 new - + statistics.currencies_count Number of currencies @@ -3271,7 +3271,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:89 new - + statistics.measurement_units_count Number of measurement units @@ -3282,7 +3282,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:93 new - + statistics.devices_count Number of devices @@ -3293,7 +3293,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:110 new - + statistics.attachment_types_count Number of attachment types @@ -3304,7 +3304,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:114 new - + statistics.all_attachments_count Number of all attachments @@ -3315,7 +3315,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:118 new - + statistics.user_uploaded_attachments_count Number of user uploaded attachments @@ -3326,7 +3326,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:122 new - + statistics.private_attachments_count Number of private attachments @@ -3337,7 +3337,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Statistics\statistics.html.twig:126 new - + statistics.external_attachments_count Number of external attachments (URL) @@ -3349,7 +3349,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:3 Part-DB1\templates\Users\backup_codes.html.twig:9 - + tfa_backup.codes.title Backup codes @@ -3359,7 +3359,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:12 Part-DB1\templates\Users\backup_codes.html.twig:12 - + tfa_backup.codes.explanation Print out these codes and keep them in a safe place! @@ -3369,7 +3369,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:13 Part-DB1\templates\Users\backup_codes.html.twig:13 - + tfa_backup.codes.help If you no longer have access to your device with the Authenticator App (lost smartphone, data loss, etc.) you can use one of these codes to access your account and possibly set up a new Authenticator App. Each of these codes can be used once, it is recommended to delete used codes. Anyone with access to these codes can potentially access your account, so keep them in a safe place. @@ -3379,7 +3379,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:16 Part-DB1\templates\Users\backup_codes.html.twig:16 - + tfa_backup.username Username @@ -3389,7 +3389,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:29 Part-DB1\templates\Users\backup_codes.html.twig:29 - + tfa_backup.codes.page_generated_on Page generated on %date% @@ -3399,7 +3399,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:32 Part-DB1\templates\Users\backup_codes.html.twig:32 - + tfa_backup.codes.print Print @@ -3409,7 +3409,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\backup_codes.html.twig:35 Part-DB1\templates\Users\backup_codes.html.twig:35 - + tfa_backup.codes.copy_clipboard Copy to clipboard @@ -3426,7 +3426,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:3 templates\Users\user_info.html.twig:6 - + user.info.label User informations @@ -3440,7 +3440,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:18 src\Form\UserSettingsType.php:32 - + user.firstName.label First name @@ -3454,7 +3454,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:24 src\Form\UserSettingsType.php:35 - + user.lastName.label Last name @@ -3468,7 +3468,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:30 src\Form\UserSettingsType.php:41 - + user.email.label Email @@ -3482,7 +3482,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:37 src\Form\UserSettingsType.php:38 - + user.department.label Department @@ -3496,7 +3496,7 @@ Sub elements will be moved upwards. templates\Users\user_info.html.twig:47 src\Form\UserSettingsType.php:30 - + user.username.label User name @@ -3509,7 +3509,7 @@ Sub elements will be moved upwards. Part-DB1\src\Services\ElementTypeNameGenerator.php:93 templates\Users\user_info.html.twig:53 - + group.label Group: @@ -3519,7 +3519,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\user_info.html.twig:67 Part-DB1\templates\Users\user_info.html.twig:67 - + user.permissions Permissions @@ -3536,7 +3536,7 @@ Sub elements will be moved upwards. templates\Users\user_settings.html.twig:3 templates\Users\user_settings.html.twig:6 - + user.settings.label User settings @@ -3547,7 +3547,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\user_settings.html.twig:18 templates\Users\user_settings.html.twig:14 - + user_settings.data.label Personal data @@ -3558,7 +3558,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\user_settings.html.twig:22 templates\Users\user_settings.html.twig:18 - + user_settings.configuration.label Configuration @@ -3569,7 +3569,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\user_settings.html.twig:55 templates\Users\user_settings.html.twig:48 - + user.settings.change_pw Change password @@ -3579,7 +3579,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:6 Part-DB1\templates\Users\_2fa_settings.html.twig:6 - + user.settings.2fa_settings Two-Factor Authentication @@ -3589,7 +3589,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:13 Part-DB1\templates\Users\_2fa_settings.html.twig:13 - + tfa.settings.google.tab Authenticator app @@ -3599,7 +3599,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:17 Part-DB1\templates\Users\_2fa_settings.html.twig:17 - + tfa.settings.bakup.tab Backup codes @@ -3609,7 +3609,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:21 Part-DB1\templates\Users\_2fa_settings.html.twig:21 - + tfa.settings.u2f.tab Security keys (U2F) @@ -3619,7 +3619,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:25 Part-DB1\templates\Users\_2fa_settings.html.twig:25 - + tfa.settings.trustedDevices.tab Trusted devices @@ -3629,7 +3629,7 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:33 Part-DB1\templates\Users\_2fa_settings.html.twig:33 - + tfa_google.disable.confirm_title Do you really want to disable the Authenticator App? @@ -3639,10 +3639,10 @@ Sub elements will be moved upwards. Part-DB1\templates\Users\_2fa_settings.html.twig:33 Part-DB1\templates\Users\_2fa_settings.html.twig:33 - + tfa_google.disable.confirm_message - If you disable the Authenticator App, all backup codes will be deleted, so you may need to reprint them.<br> -Also note that without two-factor authentication your account is not as well protected against attackers! + +Also note that without two-factor authentication your account is not as well protected against attackers!]]> @@ -3650,7 +3650,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:39 Part-DB1\templates\Users\_2fa_settings.html.twig:39 - + tfa_google.disabled_message Authenticator app deactivated! @@ -3660,9 +3660,9 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:48 Part-DB1\templates\Users\_2fa_settings.html.twig:48 - + tfa_google.step.download - Download an authenticator app (e.g. <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a> oder <a class="link-external" target="_blank" href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">FreeOTP Authenticator</a>) + Google Authenticator oder FreeOTP Authenticator)]]> @@ -3670,7 +3670,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:49 Part-DB1\templates\Users\_2fa_settings.html.twig:49 - + tfa_google.step.scan Scan the adjoining QR Code with the app or enter the data manually @@ -3680,7 +3680,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:50 Part-DB1\templates\Users\_2fa_settings.html.twig:50 - + tfa_google.step.input_code Enter the generated code in the field below and confirm @@ -3690,7 +3690,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:51 Part-DB1\templates\Users\_2fa_settings.html.twig:51 - + tfa_google.step.download_backup Print out your backup codes and store them in a safe place @@ -3700,7 +3700,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:58 Part-DB1\templates\Users\_2fa_settings.html.twig:58 - + tfa_google.manual_setup Manual setup @@ -3710,7 +3710,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:62 Part-DB1\templates\Users\_2fa_settings.html.twig:62 - + tfa_google.manual_setup.type Type @@ -3720,7 +3720,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:63 Part-DB1\templates\Users\_2fa_settings.html.twig:63 - + tfa_google.manual_setup.username Username @@ -3730,7 +3730,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:64 Part-DB1\templates\Users\_2fa_settings.html.twig:64 - + tfa_google.manual_setup.secret Secret @@ -3740,7 +3740,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:65 Part-DB1\templates\Users\_2fa_settings.html.twig:65 - + tfa_google.manual_setup.digit_count Digit count @@ -3750,7 +3750,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:74 Part-DB1\templates\Users\_2fa_settings.html.twig:74 - + tfa_google.enabled_message Authenticator App enabled @@ -3760,7 +3760,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:83 Part-DB1\templates\Users\_2fa_settings.html.twig:83 - + tfa_backup.disabled Backup codes disabled. Setup authenticator app to enable backup codes. @@ -3772,7 +3772,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:84 Part-DB1\templates\Users\_2fa_settings.html.twig:92 - + tfa_backup.explanation You can use these backup codes to access your account even if you lose the device with the Authenticator App. Print out the codes and keep them in a safe place. @@ -3782,7 +3782,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:88 Part-DB1\templates\Users\_2fa_settings.html.twig:88 - + tfa_backup.reset_codes.confirm_title Really reset codes? @@ -3792,7 +3792,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:88 Part-DB1\templates\Users\_2fa_settings.html.twig:88 - + tfa_backup.reset_codes.confirm_message This will delete all previous codes and generate a set of new codes. This cannot be undone. Remember to print out the new codes and store them in a safe place! @@ -3802,7 +3802,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:91 Part-DB1\templates\Users\_2fa_settings.html.twig:91 - + tfa_backup.enabled Backup codes enabled @@ -3812,7 +3812,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:99 Part-DB1\templates\Users\_2fa_settings.html.twig:99 - + tfa_backup.show_codes Show backup codes @@ -3822,7 +3822,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:114 Part-DB1\templates\Users\_2fa_settings.html.twig:114 - + tfa_u2f.table_caption Registered security keys @@ -3832,7 +3832,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:115 Part-DB1\templates\Users\_2fa_settings.html.twig:115 - + tfa_u2f.delete_u2f.confirm_title Really remove this security key? @@ -3842,7 +3842,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:116 Part-DB1\templates\Users\_2fa_settings.html.twig:116 - + tfa_u2f.delete_u2f.confirm_message If you remove this key, then no more login with this key will be possible. If no security keys remain, two-factor authentication will be disabled. @@ -3852,7 +3852,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:123 Part-DB1\templates\Users\_2fa_settings.html.twig:123 - + tfa_u2f.keys.name Key name @@ -3862,7 +3862,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:124 Part-DB1\templates\Users\_2fa_settings.html.twig:124 - + tfa_u2f.keys.added_date Registration date @@ -3872,7 +3872,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:134 Part-DB1\templates\Users\_2fa_settings.html.twig:134 - + tfa_u2f.key_delete Delete key @@ -3882,7 +3882,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:141 Part-DB1\templates\Users\_2fa_settings.html.twig:141 - + tfa_u2f.no_keys_registered No keys registered yet. @@ -3892,7 +3892,7 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:144 Part-DB1\templates\Users\_2fa_settings.html.twig:144 - + tfa_u2f.add_new_key Register new security key @@ -3902,10 +3902,10 @@ Also note that without two-factor authentication your account is not as well pro Part-DB1\templates\Users\_2fa_settings.html.twig:148 Part-DB1\templates\Users\_2fa_settings.html.twig:148 - + tfa_trustedDevices.explanation - When checking the second factor, the current computer can be marked as trustworthy, so no more two-factor checks on this computer are needed. -If you have done this incorrectly or if a computer is no longer trusted, you can reset the status of <i>all </i>computers here. + all computers here.]]> @@ -3913,7 +3913,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\Users\_2fa_settings.html.twig:149 Part-DB1\templates\Users\_2fa_settings.html.twig:149 - + tfa_trustedDevices.invalidate.confirm_title Really remove all trusted computers? @@ -3923,7 +3923,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\Users\_2fa_settings.html.twig:150 Part-DB1\templates\Users\_2fa_settings.html.twig:150 - + tfa_trustedDevices.invalidate.confirm_message You will have to perform two-factor authentication again on all computers. Make sure you have your two-factor device at hand. @@ -3933,7 +3933,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\Users\_2fa_settings.html.twig:154 Part-DB1\templates\Users\_2fa_settings.html.twig:154 - + tfa_trustedDevices.invalidate.btn Reset trusted devices @@ -3944,7 +3944,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar.html.twig:4 templates\base.html.twig:29 - + sidebar.toggle Toggle Sidebar @@ -3953,7 +3953,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar.html.twig:22 - + navbar.scanner.link Scanner @@ -3964,7 +3964,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar.html.twig:36 templates\base.html.twig:97 - + user.loggedin.label Logged in as @@ -3975,7 +3975,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar.html.twig:42 templates\base.html.twig:103 - + user.login Login @@ -3985,7 +3985,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar.html.twig:50 Part-DB1\templates\_navbar.html.twig:48 - + ui.toggle_darkmode Darkmode @@ -3999,7 +3999,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:106 src\Form\UserSettingsType.php:44 - + user.language_select Switch Language @@ -4010,7 +4010,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:4 templates\base.html.twig:49 - + search.options.label Search options @@ -4019,7 +4019,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:23 - + tags.label Tags @@ -4034,7 +4034,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\Parts\show_part_info.html.twig:36 src\Form\PartType.php:77 - + storelocation.label Store location @@ -4045,7 +4045,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:31 templates\base.html.twig:65 - + ordernumber.label.short Ordernr. @@ -4058,7 +4058,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:89 templates\base.html.twig:67 - + supplier.label Supplier @@ -4069,7 +4069,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:52 templates\base.html.twig:75 - + search.deactivateBarcode Deact. Barcode @@ -4080,7 +4080,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:56 templates\base.html.twig:77 - + search.regexmatching Reg.Ex. Matching @@ -4090,7 +4090,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\_navbar_search.html.twig:68 Part-DB1\templates\_navbar_search.html.twig:62 - + search.submit Go! @@ -4106,7 +4106,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:202 templates\base.html.twig:230 - + device.labelp Devices @@ -4119,7 +4119,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:192 templates\base.html.twig:220 - + actions Actions @@ -4132,7 +4132,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:196 templates\base.html.twig:224 - + datasource Datasource @@ -4145,7 +4145,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:200 templates\base.html.twig:228 - + manufacturer.labelp Manufacturers @@ -4158,7 +4158,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:201 templates\base.html.twig:229 - + supplier.labelp Suppliers @@ -4174,7 +4174,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\PartController.php:173 Part-DB1\src\Controller\PartController.php:268 - + attachment.download_failed Download of the external attachment failed. @@ -4184,7 +4184,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\AdminPages\BaseAdminController.php:222 Part-DB1\src\Controller\AdminPages\BaseAdminController.php:190 - + entity.edit_flash Changes saved successful. @@ -4194,7 +4194,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\AdminPages\BaseAdminController.php:231 Part-DB1\src\Controller\AdminPages\BaseAdminController.php:196 - + entity.edit_flash.invalid Can not save changed. Please check your input! @@ -4204,7 +4204,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\AdminPages\BaseAdminController.php:302 Part-DB1\src\Controller\AdminPages\BaseAdminController.php:252 - + entity.created_flash Element created. @@ -4214,7 +4214,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\AdminPages\BaseAdminController.php:308 Part-DB1\src\Controller\AdminPages\BaseAdminController.php:258 - + entity.created_flash.invalid Could not create element. Please check your input! @@ -4225,7 +4225,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\AdminPages\BaseAdminController.php:352 src\Controller\BaseAdminController.php:154 - + attachment_type.deleted Element deleted! @@ -4241,7 +4241,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:150 Part-DB1\src\Controller\UserSettingsController.php:182 - + csfr_invalid CSFR Token invalid. Please reload this page or contact an administrator if this message stays. @@ -4250,7 +4250,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LabelController.php:125 - + label_generator.no_entities_found No entities matching the range found. @@ -4261,7 +4261,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:154 new - + log.undo.target_not_found Target element could not be found in DB! @@ -4272,7 +4272,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:160 new - + log.undo.revert_success Reverted to timestamp successfully. @@ -4283,7 +4283,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:180 new - + log.undo.element_undelete_success Undeleted element successfully. @@ -4294,7 +4294,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:182 new - + log.undo.element_element_already_undeleted Element was already undeleted! @@ -4305,7 +4305,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:189 new - + log.undo.element_delete_success Element deleted successfully. @@ -4316,7 +4316,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:191 new - + log.undo.element.element_already_delted Element was already deleted! @@ -4327,7 +4327,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:198 new - + log.undo.element_change_undone Change undone successfully! @@ -4338,7 +4338,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:200 new - + log.undo.do_undelete_before You have to undelete the element before you can undo this change! @@ -4349,7 +4349,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\LogController.php:203 new - + log.undo.log_type_invalid This log entry can not be undone! @@ -4360,7 +4360,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\PartController.php:182 src\Controller\PartController.php:80 - + part.edited_flash Saved changes! @@ -4370,7 +4370,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\PartController.php:186 Part-DB1\src\Controller\PartController.php:186 - + part.edited_flash.invalid Error during saving: Please check your inputs! @@ -4380,7 +4380,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\PartController.php:216 Part-DB1\src\Controller\PartController.php:219 - + part.deleted Part deleted successful. @@ -4393,7 +4393,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can src\Controller\PartController.php:113 src\Controller\PartController.php:142 - + part.created_flash Part created! @@ -4403,7 +4403,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\PartController.php:308 Part-DB1\src\Controller\PartController.php:283 - + part.created_flash.invalid Error during creation: Please check your inputs! @@ -4413,7 +4413,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\ScanController.php:68 Part-DB1\src\Controller\ScanController.php:90 - + scan.qr_not_found No element found for the given barcode. @@ -4422,7 +4422,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\ScanController.php:71 - + scan.format_unknown Format unknown! @@ -4431,7 +4431,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\ScanController.php:86 - + scan.qr_success Element found. @@ -4441,7 +4441,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:114 Part-DB1\src\Controller\SecurityController.php:109 - + pw_reset.user_or_email Username / Email @@ -4451,7 +4451,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:131 Part-DB1\src\Controller\SecurityController.php:126 - + pw_reset.request.success Reset request was successful! Please check your emails for further instructions. @@ -4461,7 +4461,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:162 Part-DB1\src\Controller\SecurityController.php:160 - + pw_reset.username Username @@ -4471,7 +4471,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:165 Part-DB1\src\Controller\SecurityController.php:163 - + pw_reset.token Token @@ -4481,7 +4481,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:194 Part-DB1\src\Controller\SecurityController.php:192 - + pw_reset.new_pw.error Username or Token invalid! Please check your input. @@ -4491,7 +4491,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\SecurityController.php:196 Part-DB1\src\Controller\SecurityController.php:194 - + pw_reset.new_pw.success Password was reset successfully. You can now login with your new password. @@ -4501,7 +4501,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserController.php:107 Part-DB1\src\Controller\UserController.php:99 - + user.edit.reset_success All two-factor authentication methods were successfully disabled. @@ -4511,7 +4511,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:101 Part-DB1\src\Controller\UserSettingsController.php:92 - + tfa_backup.no_codes_enabled No backup codes enabled! @@ -4521,7 +4521,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:138 Part-DB1\src\Controller\UserSettingsController.php:132 - + tfa_u2f.u2f_delete.not_existing No security key with this ID is existing. @@ -4531,7 +4531,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:145 Part-DB1\src\Controller\UserSettingsController.php:139 - + tfa_u2f.u2f_delete.access_denied You can not delete the security keys of other users! @@ -4541,7 +4541,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:153 Part-DB1\src\Controller\UserSettingsController.php:147 - + tfa.u2f.u2f_delete.success Security key successfully removed. @@ -4551,7 +4551,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:188 Part-DB1\src\Controller\UserSettingsController.php:180 - + tfa_trustedDevice.invalidate.success Trusted devices successfully reset. @@ -4562,7 +4562,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:226 src\Controller\UserController.php:98 - + user.settings.saved_flash Settings saved! @@ -4573,7 +4573,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:288 src\Controller\UserController.php:130 - + user.settings.pw_changed_flash Password changed! @@ -4583,7 +4583,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:317 Part-DB1\src\Controller\UserSettingsController.php:306 - + user.settings.2fa.google.activated Authenticator App successfully activated. @@ -4593,7 +4593,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:328 Part-DB1\src\Controller\UserSettingsController.php:315 - + user.settings.2fa.google.disabled Authenticator App successfully deactivated. @@ -4603,7 +4603,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Controller\UserSettingsController.php:346 Part-DB1\src\Controller\UserSettingsController.php:332 - + user.settings.2fa.backup_codes.regenerated New backup codes successfully generated. @@ -4613,7 +4613,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\AttachmentDataTable.php:148 Part-DB1\src\DataTables\AttachmentDataTable.php:148 - + attachment.table.filename File name @@ -4623,7 +4623,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\AttachmentDataTable.php:153 Part-DB1\src\DataTables\AttachmentDataTable.php:153 - + attachment.table.filesize File size @@ -4643,7 +4643,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:193 Part-DB1\src\DataTables\PartsDataTable.php:200 - + true true @@ -4665,7 +4665,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:201 Part-DB1\src\Form\Type\SIUnitType.php:139 - + false false @@ -4675,7 +4675,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\Column\LogEntryTargetColumn.php:128 Part-DB1\src\DataTables\Column\LogEntryTargetColumn.php:119 - + log.target_deleted deleted @@ -4686,7 +4686,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\Column\RevertLogColumn.php:60 new - + log.undo.undelete Undelete element @@ -4697,7 +4697,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\Column\RevertLogColumn.php:66 new - + log.undo.undo Undo change @@ -4708,7 +4708,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\Column\RevertLogColumn.php:86 new - + log.undo.revert Revert element to this timestamp @@ -4718,7 +4718,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:173 Part-DB1\src\DataTables\LogDataTable.php:161 - + log.id ID @@ -4728,7 +4728,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:178 Part-DB1\src\DataTables\LogDataTable.php:166 - + log.timestamp Timestamp @@ -4738,7 +4738,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:183 Part-DB1\src\DataTables\LogDataTable.php:171 - + log.type Event @@ -4748,7 +4748,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:191 Part-DB1\src\DataTables\LogDataTable.php:179 - + log.level Level @@ -4758,7 +4758,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:200 Part-DB1\src\DataTables\LogDataTable.php:188 - + log.user User @@ -4768,7 +4768,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:213 Part-DB1\src\DataTables\LogDataTable.php:201 - + log.target_type Target type @@ -4778,7 +4778,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:226 Part-DB1\src\DataTables\LogDataTable.php:214 - + log.target Target @@ -4789,7 +4789,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\LogDataTable.php:218 new - + log.extra Extra @@ -4799,7 +4799,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:168 Part-DB1\src\DataTables\PartsDataTable.php:116 - + part.table.name Name @@ -4809,7 +4809,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:178 Part-DB1\src\DataTables\PartsDataTable.php:126 - + part.table.id Id @@ -4819,7 +4819,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:182 Part-DB1\src\DataTables\PartsDataTable.php:130 - + part.table.description Description @@ -4829,7 +4829,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:185 Part-DB1\src\DataTables\PartsDataTable.php:133 - + part.table.category Category @@ -4839,7 +4839,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:190 Part-DB1\src\DataTables\PartsDataTable.php:138 - + part.table.footprint Footprint @@ -4849,7 +4849,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:194 Part-DB1\src\DataTables\PartsDataTable.php:142 - + part.table.manufacturer Manufacturer @@ -4859,7 +4859,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:197 Part-DB1\src\DataTables\PartsDataTable.php:145 - + part.table.storeLocations Store locations @@ -4869,7 +4869,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:216 Part-DB1\src\DataTables\PartsDataTable.php:164 - + part.table.amount Amount @@ -4879,7 +4879,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:224 Part-DB1\src\DataTables\PartsDataTable.php:172 - + part.table.minamount Min. Amount @@ -4889,7 +4889,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:232 Part-DB1\src\DataTables\PartsDataTable.php:180 - + part.table.partUnit Measurement Unit @@ -4899,7 +4899,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:236 Part-DB1\src\DataTables\PartsDataTable.php:184 - + part.table.addedDate Created at @@ -4909,7 +4909,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:240 Part-DB1\src\DataTables\PartsDataTable.php:188 - + part.table.lastModified Last modified @@ -4919,7 +4919,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:244 Part-DB1\src\DataTables\PartsDataTable.php:192 - + part.table.needsReview Needs review @@ -4929,7 +4929,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:251 Part-DB1\src\DataTables\PartsDataTable.php:199 - + part.table.favorite Favorite @@ -4939,7 +4939,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:258 Part-DB1\src\DataTables\PartsDataTable.php:206 - + part.table.manufacturingStatus Status @@ -4953,7 +4953,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:210 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.unknown Unknown @@ -4965,7 +4965,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:211 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.announced Announced @@ -4977,7 +4977,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:212 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.active Active @@ -4989,7 +4989,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:213 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.nrfnd Not recommended for new designs @@ -5001,7 +5001,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:214 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.eol End of life @@ -5013,7 +5013,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:215 Part-DB1\src\Form\Part\PartBaseType.php:88 - + m_status.discontinued Discontinued @@ -5023,7 +5023,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:271 Part-DB1\src\DataTables\PartsDataTable.php:219 - + part.table.mpn MPN @@ -5033,7 +5033,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:275 Part-DB1\src\DataTables\PartsDataTable.php:223 - + part.table.mass Mass @@ -5043,7 +5043,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:279 Part-DB1\src\DataTables\PartsDataTable.php:227 - + part.table.tags Tags @@ -5053,7 +5053,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\DataTables\PartsDataTable.php:283 Part-DB1\src\DataTables\PartsDataTable.php:231 - + part.table.attachments Attachments @@ -5063,7 +5063,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\EventSubscriber\UserSystem\LoginSuccessSubscriber.php:82 Part-DB1\src\EventSubscriber\LoginSuccessListener.php:82 - + flash.login_successful Login successful @@ -5074,7 +5074,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:77 src\Form\ImportType.php:68 - + JSON JSON @@ -5085,7 +5085,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:77 src\Form\ImportType.php:68 - + XML XML @@ -5096,7 +5096,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:77 src\Form\ImportType.php:68 - + CSV CSV @@ -5107,7 +5107,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:77 src\Form\ImportType.php:68 - + YAML YAML @@ -5117,7 +5117,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:124 Part-DB1\src\Form\AdminPages\ImportType.php:124 - + import.abort_on_validation.help When this option is activated, the whole import process is aborted if invalid data is detected. If not selected, the invalid data is ignored and the importer will try to import the other elements. @@ -5128,7 +5128,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:86 src\Form\ImportType.php:70 - + import.csv_separator CSV separator @@ -5139,7 +5139,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:93 src\Form\ImportType.php:72 - + parent.label Parent element @@ -5150,7 +5150,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:101 src\Form\ImportType.php:75 - + import.file File @@ -5161,7 +5161,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:111 src\Form\ImportType.php:78 - + import.preserve_children Preserve child elements on import @@ -5172,7 +5172,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:120 src\Form\ImportType.php:80 - + import.abort_on_validation Abort on invalid data @@ -5183,7 +5183,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AdminPages\ImportType.php:132 src\Form\ImportType.php:85 - + import.btn Import @@ -5193,7 +5193,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:113 Part-DB1\src\Form\AttachmentFormType.php:109 - + attachment.edit.secure_file.help An attachment marked private can only be accessed by authenticated users with the proper permission. If this is activated no thumbnails are generated and access to file is less performant. @@ -5203,7 +5203,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:127 Part-DB1\src\Form\AttachmentFormType.php:123 - + attachment.edit.url.help You can specify an URL to an external file here, or input an keyword which is used to search in built-in resources (e.g. footprints) @@ -5213,7 +5213,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:82 Part-DB1\src\Form\AttachmentFormType.php:79 - + attachment.edit.name Name @@ -5223,7 +5223,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:85 Part-DB1\src\Form\AttachmentFormType.php:82 - + attachment.edit.attachment_type Attachment type @@ -5233,7 +5233,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:94 Part-DB1\src\Form\AttachmentFormType.php:91 - + attachment.edit.show_in_table Show in table @@ -5243,7 +5243,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:105 Part-DB1\src\Form\AttachmentFormType.php:102 - + attachment.edit.secure_file Private attachment @@ -5253,7 +5253,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:119 Part-DB1\src\Form\AttachmentFormType.php:115 - + attachment.edit.url URL @@ -5263,7 +5263,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:133 Part-DB1\src\Form\AttachmentFormType.php:129 - + attachment.edit.download_url Download external file @@ -5273,7 +5273,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\AttachmentFormType.php:146 Part-DB1\src\Form\AttachmentFormType.php:142 - + attachment.edit.file Upload file @@ -5283,7 +5283,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:68 Part-DB1\src\Services\ElementTypeNameGenerator.php:86 - + part.label Part @@ -5293,7 +5293,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:68 Part-DB1\src\Services\ElementTypeNameGenerator.php:87 - + part_lot.label Part lot @@ -5302,7 +5302,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.none None @@ -5311,7 +5311,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.qr QR Code (recommended) @@ -5320,7 +5320,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.code128 Code 128 (recommended) @@ -5329,7 +5329,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.code39 Code 39 (recommended) @@ -5338,7 +5338,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.code93 Code 93 @@ -5347,7 +5347,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:78 - + label_options.barcode_type.datamatrix Datamatrix @@ -5356,7 +5356,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:122 - + label_options.lines_mode.html Placeholders @@ -5365,7 +5365,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:122 - + label.options.lines_mode.twig Twig @@ -5374,16 +5374,16 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:126 - + label_options.lines_mode.help - If you select Twig here, the content field is interpreted as Twig template. See <a href="https://twig.symfony.com/doc/3.x/templates.html">Twig documentation</a> and <a href="https://github.com/Part-DB/Part-DB-symfony/wiki/Labels#twig-mode">Wiki</a> for more informations. + Twig documentation and Wiki for more informations.]]> Part-DB1\src\Form\LabelOptionsType.php:47 - + label_options.page_size.label Label size @@ -5392,7 +5392,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:66 - + label_options.supported_elements.label Target type @@ -5401,7 +5401,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:75 - + label_options.barcode_type.label Barcode @@ -5410,7 +5410,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:102 - + label_profile.lines.label Content @@ -5419,7 +5419,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:111 - + label_options.additional_css.label Additional styles (CSS) @@ -5428,7 +5428,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:120 - + label_options.lines_mode.label Parser mode @@ -5437,7 +5437,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:51 - + label_options.width.placeholder Width @@ -5446,7 +5446,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelOptionsType.php:60 - + label_options.height.placeholder Height @@ -5455,7 +5455,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelSystem\LabelDialogType.php:49 - + label_generator.target_id.range_hint You can specify multiple IDs (e.g. 1,2,3) and/or a range (1-3) here to generate labels for multiple elements at once. @@ -5464,7 +5464,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelSystem\LabelDialogType.php:46 - + label_generator.target_id.label Target IDs @@ -5473,7 +5473,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelSystem\LabelDialogType.php:59 - + label_generator.update Update @@ -5482,7 +5482,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelSystem\ScanDialogType.php:36 - + scan_dialog.input Input @@ -5491,7 +5491,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\LabelSystem\ScanDialogType.php:44 - + scan_dialog.submit Submit @@ -5500,7 +5500,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:41 - + parameters.name.placeholder e.g. DC Current Gain @@ -5509,7 +5509,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:50 - + parameters.symbol.placeholder e.g. h_{FE} @@ -5518,7 +5518,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:60 - + parameters.text.placeholder e.g. Test conditions @@ -5527,7 +5527,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:71 - + parameters.max.placeholder e.g. 350 @@ -5536,7 +5536,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:82 - + parameters.min.placeholder e.g. 100 @@ -5545,7 +5545,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:93 - + parameters.typical.placeholder e.g. 200 @@ -5554,7 +5554,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:103 - + parameters.unit.placeholder e.g. V @@ -5563,7 +5563,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\ParameterType.php:114 - + parameter.group.placeholder e.g. Technical Specifications @@ -5573,7 +5573,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\OrderdetailType.php:72 Part-DB1\src\Form\Part\OrderdetailType.php:75 - + orderdetails.edit.supplierpartnr Order number @@ -5583,7 +5583,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\OrderdetailType.php:81 Part-DB1\src\Form\Part\OrderdetailType.php:84 - + orderdetails.edit.supplier Supplier @@ -5593,7 +5593,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\OrderdetailType.php:87 Part-DB1\src\Form\Part\OrderdetailType.php:90 - + orderdetails.edit.url Link to offer @@ -5603,7 +5603,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\OrderdetailType.php:93 Part-DB1\src\Form\Part\OrderdetailType.php:96 - + orderdetails.edit.obsolete No longer available @@ -5613,7 +5613,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\OrderdetailType.php:75 Part-DB1\src\Form\Part\OrderdetailType.php:78 - + orderdetails.edit.supplierpartnr.placeholder e.g. BC 547 @@ -5623,7 +5623,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:101 Part-DB1\src\Form\Part\PartBaseType.php:99 - + part.edit.name Name @@ -5633,7 +5633,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:109 Part-DB1\src\Form\Part\PartBaseType.php:107 - + part.edit.description Description @@ -5643,7 +5643,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:120 Part-DB1\src\Form\Part\PartBaseType.php:118 - + part.edit.mininstock Minimum stock @@ -5653,7 +5653,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:129 Part-DB1\src\Form\Part\PartBaseType.php:127 - + part.edit.category Category @@ -5663,7 +5663,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:135 Part-DB1\src\Form\Part\PartBaseType.php:133 - + part.edit.footprint Footprint @@ -5673,7 +5673,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:142 Part-DB1\src\Form\Part\PartBaseType.php:140 - + part.edit.tags Tags @@ -5683,7 +5683,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:154 Part-DB1\src\Form\Part\PartBaseType.php:152 - + part.edit.manufacturer.label Manufacturer @@ -5693,7 +5693,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:161 Part-DB1\src\Form\Part\PartBaseType.php:159 - + part.edit.manufacturer_url.label Link to product page @@ -5703,7 +5703,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:167 Part-DB1\src\Form\Part\PartBaseType.php:165 - + part.edit.mpn Manufacturer part number @@ -5713,7 +5713,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:173 Part-DB1\src\Form\Part\PartBaseType.php:171 - + part.edit.manufacturing_status Manufacturing status @@ -5723,7 +5723,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:181 Part-DB1\src\Form\Part\PartBaseType.php:179 - + part.edit.needs_review Needs review @@ -5733,7 +5733,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:189 Part-DB1\src\Form\Part\PartBaseType.php:187 - + part.edit.is_favorite Favorite @@ -5743,7 +5743,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:197 Part-DB1\src\Form\Part\PartBaseType.php:195 - + part.edit.mass Mass @@ -5753,7 +5753,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:203 Part-DB1\src\Form\Part\PartBaseType.php:201 - + part.edit.partUnit Measuring unit @@ -5763,7 +5763,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:212 Part-DB1\src\Form\Part\PartBaseType.php:210 - + part.edit.comment Comment @@ -5773,7 +5773,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:250 Part-DB1\src\Form\Part\PartBaseType.php:246 - + part.edit.master_attachment Preview image @@ -5784,7 +5784,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:276 src\Form\PartType.php:91 - + part.edit.save Save changes @@ -5795,7 +5795,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:277 src\Form\PartType.php:92 - + part.edit.reset Reset changes @@ -5805,7 +5805,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:105 Part-DB1\src\Form\Part\PartBaseType.php:103 - + part.edit.name.placeholder e.g. BC547 @@ -5815,7 +5815,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:115 Part-DB1\src\Form\Part\PartBaseType.php:113 - + part.edit.description.placeholder e.g. NPN 45V, 0,1A, 0,5W @@ -5825,7 +5825,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartBaseType.php:123 Part-DB1\src\Form\Part\PartBaseType.php:121 - + part.editmininstock.placeholder e.g. 1 @@ -5835,7 +5835,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:69 Part-DB1\src\Form\Part\PartLotType.php:69 - + part_lot.edit.description Description @@ -5845,7 +5845,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:78 Part-DB1\src\Form\Part\PartLotType.php:78 - + part_lot.edit.location Storage location @@ -5855,7 +5855,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:89 Part-DB1\src\Form\Part\PartLotType.php:89 - + part_lot.edit.amount Amount @@ -5865,7 +5865,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:98 Part-DB1\src\Form\Part\PartLotType.php:97 - + part_lot.edit.instock_unknown Amount unknown @@ -5875,7 +5875,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:109 Part-DB1\src\Form\Part\PartLotType.php:108 - + part_lot.edit.needs_refill Needs refill @@ -5885,7 +5885,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:120 Part-DB1\src\Form\Part\PartLotType.php:119 - + part_lot.edit.expiration_date Expiration date @@ -5895,7 +5895,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Part\PartLotType.php:128 Part-DB1\src\Form\Part\PartLotType.php:125 - + part_lot.edit.comment Comment @@ -5905,7 +5905,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Permissions\PermissionsType.php:99 Part-DB1\src\Form\Permissions\PermissionsType.php:99 - + perm.group.other Miscellaneous @@ -5915,7 +5915,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\TFAGoogleSettingsType.php:97 Part-DB1\src\Form\TFAGoogleSettingsType.php:97 - + tfa_google.enable Enable authenticator app @@ -5925,7 +5925,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\TFAGoogleSettingsType.php:101 Part-DB1\src\Form\TFAGoogleSettingsType.php:101 - + tfa_google.disable Deactivate authenticator app @@ -5935,7 +5935,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\TFAGoogleSettingsType.php:74 Part-DB1\src\Form\TFAGoogleSettingsType.php:74 - + google_confirmation Confirmation code @@ -5946,7 +5946,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:108 src\Form\UserSettingsType.php:46 - + user.timezone.label Timezone @@ -5956,7 +5956,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:133 Part-DB1\src\Form\UserSettingsType.php:132 - + user.currency.label Preferred currency @@ -5967,7 +5967,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:139 src\Form\UserSettingsType.php:53 - + save Apply changes @@ -5978,7 +5978,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:140 src\Form\UserSettingsType.php:54 - + reset Discard changes @@ -5989,7 +5989,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:104 src\Form\UserSettingsType.php:45 - + user_settings.language.placeholder Serverwide language @@ -6000,7 +6000,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\UserSettingsType.php:115 src\Form\UserSettingsType.php:48 - + user_settings.timezone.placeholder Serverwide Timezone @@ -6010,7 +6010,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:79 Part-DB1\src\Services\ElementTypeNameGenerator.php:79 - + attachment.label Attachment @@ -6020,7 +6020,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:81 Part-DB1\src\Services\ElementTypeNameGenerator.php:81 - + attachment_type.label Attachment type @@ -6030,7 +6030,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:82 Part-DB1\src\Services\ElementTypeNameGenerator.php:82 - + device.label Project @@ -6040,7 +6040,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:85 Part-DB1\src\Services\ElementTypeNameGenerator.php:85 - + measurement_unit.label Measurement unit @@ -6050,7 +6050,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:90 Part-DB1\src\Services\ElementTypeNameGenerator.php:90 - + currency.label Currency @@ -6060,7 +6060,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:91 Part-DB1\src\Services\ElementTypeNameGenerator.php:91 - + orderdetail.label Order detail @@ -6070,7 +6070,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:92 Part-DB1\src\Services\ElementTypeNameGenerator.php:92 - + pricedetail.label Price detail @@ -6080,7 +6080,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:94 Part-DB1\src\Services\ElementTypeNameGenerator.php:94 - + user.label User @@ -6089,7 +6089,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:95 - + parameter.label Parameter @@ -6098,7 +6098,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\ElementTypeNameGenerator.php:96 - + label_profile.label Label profile @@ -6109,7 +6109,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\LogSystem\LogEntryExtraFormatter.php:161 new - + log.element_deleted.old_name.unknown Unknown @@ -6119,7 +6119,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\MarkdownParser.php:73 Part-DB1\src\Services\MarkdownParser.php:73 - + markdown.loading Loading markdown. If this message does not disappear, try to reload the page. @@ -6129,7 +6129,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\PasswordResetManager.php:98 Part-DB1\src\Services\PasswordResetManager.php:98 - + pw_reset.email.subject Password reset for your Part-DB account @@ -6138,7 +6138,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:108 - + tree.tools.tools Tools @@ -6149,7 +6149,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:107 src\Services\ToolsTreeBuilder.php:74 - + tree.tools.edit Edit @@ -6160,7 +6160,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:108 src\Services\ToolsTreeBuilder.php:81 - + tree.tools.show Show @@ -6170,7 +6170,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:111 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:109 - + tree.tools.system System @@ -6179,7 +6179,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:123 - + tree.tools.tools.label_dialog Label generator @@ -6188,7 +6188,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:130 - + tree.tools.tools.label_scanner Scanner @@ -6199,7 +6199,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:126 src\Services\ToolsTreeBuilder.php:62 - + tree.tools.edit.attachment_types Attachment types @@ -6210,7 +6210,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:132 src\Services\ToolsTreeBuilder.php:64 - + tree.tools.edit.categories Categories @@ -6221,7 +6221,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:138 src\Services\ToolsTreeBuilder.php:66 - + tree.tools.edit.devices Devices @@ -6232,7 +6232,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:144 src\Services\ToolsTreeBuilder.php:68 - + tree.tools.edit.suppliers Suppliers @@ -6243,7 +6243,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:150 src\Services\ToolsTreeBuilder.php:70 - + tree.tools.edit.manufacturer Manufacturers @@ -6253,7 +6253,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:179 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:156 - + tree.tools.edit.storelocation Storage locations @@ -6263,7 +6263,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:185 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:162 - + tree.tools.edit.footprint Footprints @@ -6273,7 +6273,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:191 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:168 - + tree.tools.edit.currency Currencies @@ -6283,7 +6283,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:197 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:174 - + tree.tools.edit.measurement_unit Measurement Unit @@ -6292,7 +6292,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:203 - + tree.tools.edit.label_profile Label profiles @@ -6302,7 +6302,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:209 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:180 - + tree.tools.edit.part Part @@ -6313,7 +6313,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:197 src\Services\ToolsTreeBuilder.php:77 - + tree.tools.show.all_parts Show all parts @@ -6323,7 +6323,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:232 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:203 - + tree.tools.show.all_attachments Attachments @@ -6334,7 +6334,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:210 new - + tree.tools.show.statistics Statistics @@ -6344,7 +6344,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:258 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:229 - + tree.tools.system.users Users @@ -6354,7 +6354,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:264 Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:235 - + tree.tools.system.groups Groups @@ -6365,7 +6365,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\ToolsTreeBuilder.php:242 new - + tree.tools.system.event_log Event log @@ -6376,7 +6376,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Services\Trees\TreeViewGenerator.php:95 src\Services\TreeBuilder.php:124 - + entity.tree.new New Element @@ -6386,7 +6386,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\Parts\info\_attachments_info.html.twig:34 obsolete - + attachment.external_file External file @@ -6396,7 +6396,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\templates\Parts\info\_attachments_info.html.twig:62 obsolete - + attachment.edit Edit @@ -6407,7 +6407,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can templates\base.html.twig:88 obsolete - + barcode.scan Scan Barcode @@ -6418,7 +6418,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can src\Form\UserSettingsType.php:49 obsolete - + user.theme.label Theme @@ -6429,7 +6429,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can src\Form\UserSettingsType.php:50 obsolete - + user_settings.theme.placeholder Serverwide Theme @@ -6439,7 +6439,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Type\SIUnitType.php:141 obsolete - + M M @@ -6449,14 +6449,14 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Type\SIUnitType.php:141 obsolete - + k k - + @@ -6465,7 +6465,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Type\SIUnitType.php:141 obsolete - + m m @@ -6475,7 +6475,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can Part-DB1\src\Form\Type\SIUnitType.php:141 obsolete - + µ µ @@ -6486,7 +6486,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.user_login.ip IP @@ -6500,7 +6500,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.undo_mode.undo Change undone @@ -6514,7 +6514,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.undo_mode.revert Element reverted @@ -6525,7 +6525,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.element_created.original_instock Old instock @@ -6536,7 +6536,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.element_deleted.old_name Old name @@ -6547,7 +6547,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.element_edited.changed_fields Changed fields @@ -6558,7 +6558,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.instock_changed.comment Comment @@ -6569,7 +6569,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can new obsolete - + log.collection_deleted.deleted Deleted element: @@ -6580,7 +6580,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + go.exclamation Go! @@ -6591,7 +6591,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + language.english English @@ -6602,7 +6602,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + language.german German @@ -6612,7 +6612,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.password_change_needed Password change needed! @@ -6622,7 +6622,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment.table.type Attachment type @@ -6632,7 +6632,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment.table.element Associated element @@ -6642,7 +6642,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment.edit.isPicture Picture? @@ -6652,7 +6652,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment.edit.is3DModel 3D model? @@ -6662,7 +6662,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment.edit.isBuiltin Builtin? @@ -6672,7 +6672,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.default_comment.placeholder e.g. useful for switching @@ -6682,7 +6682,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + tfa_backup.regenerate_codes Generate new backup codes @@ -6692,7 +6692,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.noneofitschild.self A element can not be its own parent. @@ -6702,7 +6702,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.noneofitschild.children The parent can not be one of the children of itself. @@ -6712,7 +6712,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.isSelectable The element must be selectable. @@ -6722,7 +6722,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.part_lot.location_full.no_increasment The storage location was marked as full, so you can not increase the instock amount. (New amount max. {{ old_amount }}) @@ -6732,7 +6732,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.part_lot.location_full The storage location was marked as full, so you can not add a new part to it. @@ -6742,7 +6742,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.part_lot.only_existing The storage location was marked as "only existing", so you can not add new part to it. @@ -6752,7 +6752,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.part_lot.single_part The storage location was marked as "single part", so you can not add a new part to it. @@ -6762,7 +6762,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.active.help The part is currently and in forseeable future in production @@ -6772,7 +6772,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.announced.help The part was announced but is not available yet. @@ -6782,7 +6782,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.discontinued.help The part is discontinued and not produced anymore. @@ -6792,7 +6792,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.eol.help The product has reached its end-of-life and the production will be stopped soon. @@ -6802,7 +6802,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.nrfnd.help The part is currently in production but is not recommended for new designs. @@ -6812,7 +6812,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + m_status.unknown.help The manufacturing status of the part is not known. @@ -6822,7 +6822,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.success Success @@ -6832,7 +6832,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.error Error @@ -6842,7 +6842,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.warning Warning @@ -6852,7 +6852,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.notice Notice @@ -6862,7 +6862,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + flash.info Info @@ -6872,7 +6872,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + validator.noLockout You can not withdraw yourself the "change permission" permission, to prevent that you lockout yourself accidentally. @@ -6882,7 +6882,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment_type.edit.filetype_filter Allowed file extensions. @@ -6892,7 +6892,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment_type.edit.filetype_filter.help You can specify a comma separated list of file extension or mimetypes, which an uploaded file must have when assigned to this attachment type. To allow all supported image files you can use image/*. @@ -6902,7 +6902,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + attachment_type.edit.filetype_filter.placeholder e.g. .txt, application/pdf, image/* @@ -6913,7 +6913,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + part.name.placeholder e.g. BC547 @@ -6923,7 +6923,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + entity.edit.not_selectable Not selectable @@ -6933,7 +6933,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + entity.edit.not_selectable.help If this option is activated, this element can not be assigned to a part property. Useful if this element is just used for grouping. @@ -6943,7 +6943,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + bbcode.hint You can use BBCode here (e.g. [b]Bold[/b]) @@ -6953,7 +6953,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + entity.create Create element @@ -6963,7 +6963,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + entity.edit.save Save @@ -6973,7 +6973,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_footprints Disable footprints @@ -6983,7 +6983,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_footprints.help If this option is activated, the footprint property is disabled for all parts with this category. @@ -6993,7 +6993,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_manufacturers Disable manufacturers @@ -7003,7 +7003,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_manufacturers.help If this option is activated, the manufacturer property is disabled for all parts with this category. @@ -7013,7 +7013,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_autodatasheets Disable automatic datasheet links @@ -7023,7 +7023,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_autodatasheets.help If this option is activated, no automatic links to datasheets are created for parts with this category. @@ -7033,7 +7033,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_properties Disable properties @@ -7043,7 +7043,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.disable_properties.help If this option is activated, the part properties are disabled for parts with this category. @@ -7053,7 +7053,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.partname_hint Part name hint @@ -7063,7 +7063,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.partname_hint.placeholder e.g. 100nF @@ -7073,7 +7073,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.partname_regex Name filter @@ -7083,7 +7083,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.default_description Default description @@ -7093,7 +7093,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.default_description.placeholder e.g. Capacitor, 10mm x 10mm, SMD @@ -7103,7 +7103,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + category.edit.default_comment Default comment @@ -7113,7 +7113,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + company.edit.address Address @@ -7123,7 +7123,7 @@ If you have done this incorrectly or if a computer is no longer trusted, you can obsolete obsolete - + company.edit.address.placeholder e.g. Examplestreet 314 Exampletown @@ -7134,7 +7134,7 @@ Exampletown obsolete obsolete - + company.edit.phone_number Phone number @@ -7144,7 +7144,7 @@ Exampletown obsolete obsolete - + company.edit.phone_number.placeholder +49 12345 6789 @@ -7154,7 +7154,7 @@ Exampletown obsolete obsolete - + company.edit.fax_number Fax number @@ -7164,7 +7164,7 @@ Exampletown obsolete obsolete - + company.edit.email Email @@ -7174,7 +7174,7 @@ Exampletown obsolete obsolete - + company.edit.email.placeholder e.g. contact@foo.bar @@ -7184,7 +7184,7 @@ Exampletown obsolete obsolete - + company.edit.website Website @@ -7194,7 +7194,7 @@ Exampletown obsolete obsolete - + company.edit.website.placeholder https://www.foo.bar @@ -7204,7 +7204,7 @@ Exampletown obsolete obsolete - + company.edit.auto_product_url Product URL @@ -7214,7 +7214,7 @@ Exampletown obsolete obsolete - + company.edit.auto_product_url.help This field is used to determine an link to the part on the company page. %PARTNUMBER% will be replaced with the order number. @@ -7224,7 +7224,7 @@ Exampletown obsolete obsolete - + company.edit.auto_product_url.placeholder https://foo.bar/product/%PARTNUMBER% @@ -7234,7 +7234,7 @@ Exampletown obsolete obsolete - + currency.edit.iso_code ISO code @@ -7244,7 +7244,7 @@ Exampletown obsolete obsolete - + currency.edit.exchange_rate Exchange rate @@ -7254,7 +7254,7 @@ Exampletown obsolete obsolete - + footprint.edit.3d_model 3D model @@ -7264,7 +7264,7 @@ Exampletown obsolete obsolete - + mass_creation.lines Input @@ -7274,7 +7274,7 @@ Exampletown obsolete obsolete - + mass_creation.lines.placeholder Element 1 Element 2 @@ -7286,7 +7286,7 @@ Element 3 obsolete obsolete - + entity.mass_creation.btn Create @@ -7296,7 +7296,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.is_integer Is integer @@ -7306,7 +7306,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.is_integer.help If this option is activated, all values with this unit will be rounded to whole numbers. @@ -7316,7 +7316,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.use_si_prefix Use SI prefix @@ -7326,7 +7326,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.use_si_prefix.help If this option is activated, values are outputted with SI prefixes (e.g. 1,2kg instead of 1200g) @@ -7336,7 +7336,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.unit_symbol Unit symbol @@ -7346,7 +7346,7 @@ Element 3 obsolete obsolete - + measurement_unit.edit.unit_symbol.placeholder e.g. m @@ -7356,7 +7356,7 @@ Element 3 obsolete obsolete - + storelocation.edit.is_full.label Storelocation full @@ -7366,7 +7366,7 @@ Element 3 obsolete obsolete - + storelocation.edit.is_full.help If this option is selected, it is neither possible to add new parts to this storelocation or to increase the amount of existing parts. @@ -7376,7 +7376,7 @@ Element 3 obsolete obsolete - + storelocation.limit_to_existing.label Limit to existing parts @@ -7386,7 +7386,7 @@ Element 3 obsolete obsolete - + storelocation.limit_to_existing.help If this option is activated, it is not possible to add new parts to this storelocation, but the amount of existing parts can be increased. @@ -7396,7 +7396,7 @@ Element 3 obsolete obsolete - + storelocation.only_single_part.label Only single part @@ -7406,7 +7406,7 @@ Element 3 obsolete obsolete - + storelocation.only_single_part.help If this option is activated, only a single part (with every amount) can be assigned to this store location. Useful for small SMD boxes or feeders. @@ -7416,7 +7416,7 @@ Element 3 obsolete obsolete - + storelocation.storage_type.label Storage type @@ -7426,7 +7426,7 @@ Element 3 obsolete obsolete - + storelocation.storage_type.help You can select a measurement unit here, which a part must have to be able to be assigned to this storage location @@ -7436,7 +7436,7 @@ Element 3 obsolete obsolete - + supplier.edit.default_currency Default currency @@ -7446,7 +7446,7 @@ Element 3 obsolete obsolete - + supplier.shipping_costs.label Shipping Costs @@ -7456,7 +7456,7 @@ Element 3 obsolete obsolete - + user.username.placeholder e.g. j.doe @@ -7466,7 +7466,7 @@ Element 3 obsolete obsolete - + user.firstName.placeholder e.g John @@ -7476,7 +7476,7 @@ Element 3 obsolete obsolete - + user.lastName.placeholder e.g. Doe @@ -7486,7 +7486,7 @@ Element 3 obsolete obsolete - + user.email.placeholder j.doe@ecorp.com @@ -7496,7 +7496,7 @@ Element 3 obsolete obsolete - + user.department.placeholder e.g. Development @@ -7506,7 +7506,7 @@ Element 3 obsolete obsolete - + user.settings.pw_new.label New password @@ -7516,7 +7516,7 @@ Element 3 obsolete obsolete - + user.settings.pw_confirm.label Confirm new password @@ -7526,7 +7526,7 @@ Element 3 obsolete obsolete - + user.edit.needs_pw_change User needs to change password @@ -7536,7 +7536,7 @@ Element 3 obsolete obsolete - + user.edit.user_disabled User disabled (no login possible) @@ -7546,7 +7546,7 @@ Element 3 obsolete obsolete - + user.create Create user @@ -7556,7 +7556,7 @@ Element 3 obsolete obsolete - + user.edit.save Save @@ -7566,7 +7566,7 @@ Element 3 obsolete obsolete - + entity.edit.reset Discard changes @@ -7577,7 +7577,7 @@ Element 3 obsolete obsolete - + part.withdraw.caption: Withdraw parts: @@ -7588,7 +7588,7 @@ Element 3 obsolete obsolete - + part.withdraw.btn Withdraw @@ -7599,7 +7599,7 @@ Element 3 obsolete obsolete - + part.withdraw.comment: Comment/Purpose @@ -7610,7 +7610,7 @@ Element 3 obsolete obsolete - + part.add.caption Add parts @@ -7621,7 +7621,7 @@ Element 3 obsolete obsolete - + part.add.btn Add @@ -7632,7 +7632,7 @@ Element 3 obsolete obsolete - + part.add.comment Comment/Purpose @@ -7643,7 +7643,7 @@ Element 3 obsolete obsolete - + admin.comment Comment @@ -7654,7 +7654,7 @@ Element 3 obsolete obsolete - + manufacturer_url.label Manufacturer link @@ -7665,7 +7665,7 @@ Element 3 obsolete obsolete - + part.description.placeholder e.g. NPN 45V 0,1A 0,5W @@ -7676,7 +7676,7 @@ Element 3 obsolete obsolete - + part.instock.placeholder e.g. 10 @@ -7687,7 +7687,7 @@ Element 3 obsolete obsolete - + part.mininstock.placeholder e.g. 5 @@ -7697,7 +7697,7 @@ Element 3 obsolete obsolete - + homepage.basedOn Based on work of @@ -7707,7 +7707,7 @@ Element 3 obsolete obsolete - + homepage.others and others @@ -7717,7 +7717,7 @@ Element 3 obsolete obsolete - + part.order.price_per Price per @@ -7727,7 +7727,7 @@ Element 3 obsolete obsolete - + part.withdraw.caption Withdraw parts @@ -7737,7 +7737,7 @@ Element 3 obsolete obsolete - + datatable.datatable.lengthMenu _MENU_ @@ -7747,7 +7747,7 @@ Element 3 obsolete obsolete - + perm.group.parts Parts @@ -7757,7 +7757,7 @@ Element 3 obsolete obsolete - + perm.group.structures Data structures @@ -7767,7 +7767,7 @@ Element 3 obsolete obsolete - + perm.group.system System @@ -7777,9 +7777,9 @@ Element 3 obsolete obsolete - + perm.parts - Common + Parts @@ -7787,7 +7787,7 @@ Element 3 obsolete obsolete - + perm.read View @@ -7797,7 +7797,7 @@ Element 3 obsolete obsolete - + perm.edit Edit @@ -7807,7 +7807,7 @@ Element 3 obsolete obsolete - + perm.create Create @@ -7817,7 +7817,7 @@ Element 3 obsolete obsolete - + perm.part.move Change category @@ -7827,7 +7827,7 @@ Element 3 obsolete obsolete - + perm.delete Delete @@ -7837,7 +7837,7 @@ Element 3 obsolete obsolete - + perm.part.search Search @@ -7847,7 +7847,7 @@ Element 3 obsolete obsolete - + perm.part.all_parts List all parts @@ -7857,7 +7857,7 @@ Element 3 obsolete obsolete - + perm.part.no_price_parts List parts without price infos @@ -7867,7 +7867,7 @@ Element 3 obsolete obsolete - + perm.part.obsolete_parts List obsolete parts @@ -7877,7 +7877,7 @@ Element 3 obsolete obsolete - + perm.part.unknown_instock_parts Show parts with unknown instock @@ -7887,7 +7887,7 @@ Element 3 obsolete obsolete - + perm.part.change_favorite Change favorite status @@ -7897,7 +7897,7 @@ Element 3 obsolete obsolete - + perm.part.show_favorite List favorite parts @@ -7907,7 +7907,7 @@ Element 3 obsolete obsolete - + perm.part.show_last_edit_parts Show last edited/added parts @@ -7917,7 +7917,7 @@ Element 3 obsolete obsolete - + perm.part.show_users Show last modifying user @@ -7927,7 +7927,7 @@ Element 3 obsolete obsolete - + perm.part.show_history Show history @@ -7937,7 +7937,7 @@ Element 3 obsolete obsolete - + perm.part.name Name @@ -7947,7 +7947,7 @@ Element 3 obsolete obsolete - + perm.part.description Description @@ -7957,7 +7957,7 @@ Element 3 obsolete obsolete - + perm.part.instock Instock @@ -7967,7 +7967,7 @@ Element 3 obsolete obsolete - + perm.part.mininstock Minimum instock @@ -7977,7 +7977,7 @@ Element 3 obsolete obsolete - + perm.part.comment Comment @@ -7987,7 +7987,7 @@ Element 3 obsolete obsolete - + perm.part.storelocation Storelocation @@ -7997,7 +7997,7 @@ Element 3 obsolete obsolete - + perm.part.manufacturer Manufacturer @@ -8007,7 +8007,7 @@ Element 3 obsolete obsolete - + perm.part.orderdetails Order informations @@ -8017,7 +8017,7 @@ Element 3 obsolete obsolete - + perm.part.prices Prices @@ -8027,7 +8027,7 @@ Element 3 obsolete obsolete - + perm.part.attachments File attachments @@ -8037,7 +8037,7 @@ Element 3 obsolete obsolete - + perm.part.order Orders @@ -8047,7 +8047,7 @@ Element 3 obsolete obsolete - + perm.storelocations Storelocations @@ -8057,7 +8057,7 @@ Element 3 obsolete obsolete - + perm.move Move @@ -8067,7 +8067,7 @@ Element 3 obsolete obsolete - + perm.list_parts List parts @@ -8077,7 +8077,7 @@ Element 3 obsolete obsolete - + perm.part.footprints Footprints @@ -8087,7 +8087,7 @@ Element 3 obsolete obsolete - + perm.part.categories Categories @@ -8097,7 +8097,7 @@ Element 3 obsolete obsolete - + perm.part.supplier Suppliers @@ -8107,7 +8107,7 @@ Element 3 obsolete obsolete - + perm.part.manufacturers Manufacturers @@ -8117,7 +8117,7 @@ Element 3 obsolete obsolete - + perm.part.devices Devices @@ -8127,7 +8127,7 @@ Element 3 obsolete obsolete - + perm.part.attachment_types Attachment types @@ -8137,7 +8137,7 @@ Element 3 obsolete obsolete - + perm.tools.import Import @@ -8147,7 +8147,7 @@ Element 3 obsolete obsolete - + perm.tools.labels Labels @@ -8157,7 +8157,7 @@ Element 3 obsolete obsolete - + perm.tools.calculator Resistor calculator @@ -8167,7 +8167,7 @@ Element 3 obsolete obsolete - + perm.tools.footprints Footprints @@ -8177,7 +8177,7 @@ Element 3 obsolete obsolete - + perm.tools.ic_logos IC logos @@ -8187,7 +8187,7 @@ Element 3 obsolete obsolete - + perm.tools.statistics Statistics @@ -8197,7 +8197,7 @@ Element 3 obsolete obsolete - + perm.edit_permissions Edit permissions @@ -8207,7 +8207,7 @@ Element 3 obsolete obsolete - + perm.users.edit_user_name Edit user name @@ -8217,7 +8217,7 @@ Element 3 obsolete obsolete - + perm.users.edit_change_group Change group @@ -8227,7 +8227,7 @@ Element 3 obsolete obsolete - + perm.users.edit_infos Edit infos @@ -8237,7 +8237,7 @@ Element 3 obsolete obsolete - + perm.users.edit_permissions Edit permissions @@ -8247,7 +8247,7 @@ Element 3 obsolete obsolete - + perm.users.set_password Set password @@ -8257,7 +8257,7 @@ Element 3 obsolete obsolete - + perm.users.change_user_settings Change user settings @@ -8267,7 +8267,7 @@ Element 3 obsolete obsolete - + perm.database.see_status Show status @@ -8277,7 +8277,7 @@ Element 3 obsolete obsolete - + perm.database.update_db Update DB @@ -8287,7 +8287,7 @@ Element 3 obsolete obsolete - + perm.database.read_db_settings Read DB settings @@ -8297,7 +8297,7 @@ Element 3 obsolete obsolete - + perm.database.write_db_settings Write DB settings @@ -8307,7 +8307,7 @@ Element 3 obsolete obsolete - + perm.config.read_config Read config @@ -8317,7 +8317,7 @@ Element 3 obsolete obsolete - + perm.config.edit_config Edit config @@ -8327,7 +8327,7 @@ Element 3 obsolete obsolete - + perm.config.server_info Server info @@ -8337,7 +8337,7 @@ Element 3 obsolete obsolete - + perm.config.use_debug Use debug tools @@ -8347,7 +8347,7 @@ Element 3 obsolete obsolete - + perm.show_logs Show logs @@ -8357,7 +8357,7 @@ Element 3 obsolete obsolete - + perm.delete_logs Delete logs @@ -8367,7 +8367,7 @@ Element 3 obsolete obsolete - + perm.self.edit_infos Edit infos @@ -8377,7 +8377,7 @@ Element 3 obsolete obsolete - + perm.self.edit_username Edit username @@ -8387,7 +8387,7 @@ Element 3 obsolete obsolete - + perm.self.show_permissions View permissions @@ -8397,7 +8397,7 @@ Element 3 obsolete obsolete - + perm.self.show_logs Show own log entries @@ -8407,7 +8407,7 @@ Element 3 obsolete obsolete - + perm.self.create_labels Create labels @@ -8417,7 +8417,7 @@ Element 3 obsolete obsolete - + perm.self.edit_options Edit options @@ -8427,7 +8427,7 @@ Element 3 obsolete obsolete - + perm.self.delete_profiles Delete profiles @@ -8437,7 +8437,7 @@ Element 3 obsolete obsolete - + perm.self.edit_profiles Edit profiles @@ -8447,7 +8447,7 @@ Element 3 obsolete obsolete - + perm.part.tools Tools @@ -8457,7 +8457,7 @@ Element 3 obsolete obsolete - + perm.groups Groups @@ -8467,7 +8467,7 @@ Element 3 obsolete obsolete - + perm.users Users @@ -8477,7 +8477,7 @@ Element 3 obsolete obsolete - + perm.database Database @@ -8487,7 +8487,7 @@ Element 3 obsolete obsolete - + perm.config Configuration @@ -8497,7 +8497,7 @@ Element 3 obsolete obsolete - + perm.system System @@ -8507,7 +8507,7 @@ Element 3 obsolete obsolete - + perm.device_parts Device parts @@ -8517,7 +8517,7 @@ Element 3 obsolete obsolete - + perm.self Own user @@ -8527,7 +8527,7 @@ Element 3 obsolete obsolete - + perm.labels Labels @@ -8537,7 +8537,7 @@ Element 3 obsolete obsolete - + perm.part.category Category @@ -8547,7 +8547,7 @@ Element 3 obsolete obsolete - + perm.part.minamount Minimum amount @@ -8557,7 +8557,7 @@ Element 3 obsolete obsolete - + perm.part.footprint Footprint @@ -8567,7 +8567,7 @@ Element 3 obsolete obsolete - + perm.part.mpn MPN @@ -8577,7 +8577,7 @@ Element 3 obsolete obsolete - + perm.part.status Manufacturing status @@ -8587,7 +8587,7 @@ Element 3 obsolete obsolete - + perm.part.tags Tags @@ -8597,7 +8597,7 @@ Element 3 obsolete obsolete - + perm.part.unit Part unit @@ -8607,7 +8607,7 @@ Element 3 obsolete obsolete - + perm.part.mass Mass @@ -8617,7 +8617,7 @@ Element 3 obsolete obsolete - + perm.part.lots Part lots @@ -8627,7 +8627,7 @@ Element 3 obsolete obsolete - + perm.show_users Show last modifying user @@ -8637,7 +8637,7 @@ Element 3 obsolete obsolete - + perm.currencies Currencies @@ -8647,7 +8647,7 @@ Element 3 obsolete obsolete - + perm.measurement_units Measurement unit @@ -8657,7 +8657,7 @@ Element 3 obsolete obsolete - + user.settings.pw_old.label Old password @@ -8667,7 +8667,7 @@ Element 3 obsolete obsolete - + pw_reset.submit Reset password @@ -8677,7 +8677,7 @@ Element 3 obsolete obsolete - + u2f_two_factor Security key (U2F) @@ -8687,13 +8687,13 @@ Element 3 obsolete obsolete - + google Google - - + + tfa.provider.webauthn_two_factor_provider Security key @@ -8703,7 +8703,7 @@ Element 3 obsolete obsolete - + tfa.provider.google Authenticator app @@ -8713,7 +8713,7 @@ Element 3 obsolete obsolete - + Login successful Login successful @@ -8723,7 +8723,7 @@ Element 3 obsolete obsolete - + log.type.exception Unhandled exception (obsolete) @@ -8733,7 +8733,7 @@ Element 3 obsolete obsolete - + log.type.user_login User login @@ -8743,7 +8743,7 @@ Element 3 obsolete obsolete - + log.type.user_logout User logout @@ -8753,7 +8753,7 @@ Element 3 obsolete obsolete - + log.type.unknown Unknown @@ -8763,7 +8763,7 @@ Element 3 obsolete obsolete - + log.type.element_created Element created @@ -8773,7 +8773,7 @@ Element 3 obsolete obsolete - + log.type.element_edited Element edited @@ -8783,7 +8783,7 @@ Element 3 obsolete obsolete - + log.type.element_deleted Element deleted @@ -8793,7 +8793,7 @@ Element 3 obsolete obsolete - + log.type.database_updated Database updated @@ -8802,7 +8802,7 @@ Element 3 obsolete - + perm.revert_elements Revert element @@ -8811,7 +8811,7 @@ Element 3 obsolete - + perm.show_history Show history @@ -8820,7 +8820,7 @@ Element 3 obsolete - + perm.tools.lastActivity Show last activity @@ -8829,7 +8829,7 @@ Element 3 obsolete - + perm.tools.timeTravel Show old element versions (time travel) @@ -8838,7 +8838,7 @@ Element 3 obsolete - + log.type. __log.type. @@ -8847,7 +8847,7 @@ Element 3 obsolete - + tfa_u2f.key_added_successful Security key added successfully. @@ -8856,7 +8856,7 @@ Element 3 obsolete - + Username Username @@ -8865,7 +8865,7 @@ Element 3 obsolete - + log.type.security.google_disabled Authenticator App disabled @@ -8874,7 +8874,7 @@ Element 3 obsolete - + log.type.security.u2f_removed Security key removed @@ -8883,7 +8883,7 @@ Element 3 obsolete - + log.type.security.u2f_added Security key added @@ -8892,7 +8892,7 @@ Element 3 obsolete - + log.type.security.backup_keys_reset Backup keys regenerated @@ -8901,7 +8901,7 @@ Element 3 obsolete - + log.type.security.google_enabled Authenticator App enabled @@ -8910,7 +8910,7 @@ Element 3 obsolete - + log.type.security.password_changed Password changed @@ -8919,7 +8919,7 @@ Element 3 obsolete - + log.type.security.trusted_device_reset Trusted devices resetted @@ -8928,7 +8928,7 @@ Element 3 obsolete - + log.type.collection_element_deleted Element of Collection deleted @@ -8937,7 +8937,7 @@ Element 3 obsolete - + log.type.security.password_reset Password reset @@ -8946,7 +8946,7 @@ Element 3 obsolete - + log.type.security.2fa_admin_reset Two Factor Reset by Administrator @@ -8955,7 +8955,7 @@ Element 3 obsolete - + log.type.user_not_allowed Unauthorized access attempt @@ -8964,7 +8964,7 @@ Element 3 obsolete - + log.database_updated.success Success @@ -8973,7 +8973,7 @@ Element 3 obsolete - + label_options.barcode_type.2D 2D @@ -8982,7 +8982,7 @@ Element 3 obsolete - + label_options.barcode_type.1D 1D @@ -8991,7 +8991,7 @@ Element 3 obsolete - + perm.part.parameters Parameters @@ -9000,7 +9000,7 @@ Element 3 obsolete - + perm.attachment_show_private View private attachments @@ -9009,7 +9009,7 @@ Element 3 obsolete - + perm.tools.label_scanner Label scanner @@ -9018,7 +9018,7 @@ Element 3 obsolete - + perm.self.read_profiles Read profiles @@ -9027,7 +9027,7 @@ Element 3 obsolete - + perm.self.create_profiles Create profiles @@ -9036,742 +9036,856 @@ Element 3 obsolete - + perm.labels.use_twig Use twig mode - + label_profile.showInDropdown Show in quick select - + group.edit.enforce_2fa Enforce Two-factor authentication (2FA) - + group.edit.enforce_2fa.help If this option is enabled, every direct member of this group, has to configure at least one second-factor for authentication. Recommended for administrative groups with much permissions. - + selectpicker.empty Nothing selected - + selectpicker.nothing_selected Nothing selected - + entity.delete.must_not_contain_parts Element "%PATH%" still contains parts! You have to move the parts, to be able to delete this element. - + entity.delete.must_not_contain_attachments Attachment type still contains attachments. Change their type, to be able to delete this attachment type. - + entity.delete.must_not_contain_prices Currency still contains pricedetails. You have to change their currency to be able to delete this element. - + entity.delete.must_not_contain_users Users still uses this group! Change their group, to be able to delete this group. - + part.table.edit Edit - + part.table.edit.title Edit part - + part_list.action.action.title Select action - + part_list.action.action.group.favorite Favorite status - + part_list.action.action.favorite Favorite - + part_list.action.action.unfavorite Unfavorite - + part_list.action.action.group.change_field Change field - + part_list.action.action.change_category Change category - + part_list.action.action.change_footprint Change footprint - + part_list.action.action.change_manufacturer Change manufacturer - + part_list.action.action.change_unit Change part unit - + part_list.action.action.delete Delete - + part_list.action.submit Submit - + part_list.action.part_count %count% parts selected! - + company.edit.quick.website Open website - + company.edit.quick.email Send email - + company.edit.quick.phone Call phone - + company.edit.quick.fax Send fax - + company.fax_number.placeholder e.g. +49 1234 567890 - + part.edit.save_and_clone Save and clone - + validator.file_ext_not_allowed File extension not allowed for this attachment type. - + tools.reel_calc.title SMD Reel calculator - + tools.reel_calc.inner_dia Inner diameter - + tools.reel_calc.outer_dia Outer diameter - + tools.reel_calc.tape_thick Tape thickness - + tools.reel_calc.part_distance Part distance - + tools.reel_calc.update Update - + tools.reel_calc.parts_per_meter Parts per meter - + tools.reel_calc.result_length Tape length - + tools.reel_calc.result_amount Approx. parts count - + tools.reel_calc.outer_greater_inner_error Error: Outer diameter must be greater than inner diameter! - + tools.reel_calc.missing_values.error Please fill in all values! - + tools.reel_calc.load_preset Load preset - + tools.reel_calc.explanation This calculator gives you an estimation, how many parts are remaining on an SMD reel. Measure the noted the dimensions on the reel (or use some of the presets) and click "Update" to get an result. - + perm.tools.reel_calculator SMD Reel calculator - + tree.tools.tools.reel_calculator SMD Reel calculator - + user.pw_change_needed.flash Your password needs to be changed! Please set a new password. - + tree.root_node.text Root node - + part_list.action.select_null No elements existing! - + part_list.action.delete-title Do you really want to delete these parts? - + part_list.action.delete-message These parts and any associated information (like attachments, price information, etc.) will be deleted. This can not be undone! - + part.table.actions.success Actions finished successfully. - + attachment.edit.delete.confirm Do you really want to delete this attachment? - + filter.text_constraint.value.operator.EQ Is - + filter.text_constraint.value.operator.NEQ Is not - + filter.text_constraint.value.operator.STARTS Starts with - + filter.text_constraint.value.operator.CONTAINS Contains - + filter.text_constraint.value.operator.ENDS Ends with - + filter.text_constraint.value.operator.LIKE LIKE pattern - + filter.text_constraint.value.operator.REGEX Regular expression - + filter.number_constraint.value.operator.BETWEEN Between - + filter.number_constraint.AND and - + filter.entity_constraint.operator.EQ Is (excluding children) - + filter.entity_constraint.operator.NEQ Is not (excluding children) - + filter.entity_constraint.operator.INCLUDING_CHILDREN Is (including children) - + filter.entity_constraint.operator.EXCLUDING_CHILDREN Is not (excluding children) - + part.filter.dbId Database ID - + filter.tags_constraint.operator.ANY Any of the tags - + filter.tags_constraint.operator.ALL All of the tags - + filter.tags_constraint.operator.NONE None of the tags - + part.filter.lot_count Number of lots - + part.filter.attachments_count Number of attachments - + part.filter.orderdetails_count Number of orderdetails - + part.filter.lotExpirationDate Lot expiration date - + part.filter.lotNeedsRefill Any lot needs refill - + part.filter.lotUnknwonAmount Any lot has unknown amount - + part.filter.attachmentName Attachment name - + filter.choice_constraint.operator.ANY Any of - + filter.choice_constraint.operator.NONE None of - + part.filter.amount_sum Total amount - + filter.submit Update - + filter.discard Discard changes - + filter.clear_filters Clear all filters - + filter.title Filter - + filter.parameter_value_constraint.operator.= Typ. Value = - + filter.parameter_value_constraint.operator.!= Typ. Value != - + filter.parameter_value_constraint.operator.< - Typ. Value < + - + filter.parameter_value_constraint.operator.> - Typ. Value > + ]]> - + filter.parameter_value_constraint.operator.<= - Typ. Value <= + - + filter.parameter_value_constraint.operator.>= - Typ. Value >= + =]]> - + filter.parameter_value_constraint.operator.BETWEEN Typ. Value is between - + filter.parameter_value_constraint.operator.IN_RANGE In Value range - + filter.parameter_value_constraint.operator.NOT_IN_RANGE Not in Value range - + filter.parameter_value_constraint.operator.GREATER_THAN_RANGE Greater than Value range - + filter.parameter_value_constraint.operator.GREATER_EQUAL_RANGE Greater equal than Value range - + filter.parameter_value_constraint.operator.LESS_THAN_RANGE Less than Value range - + filter.parameter_value_constraint.operator.LESS_EQUAL_RANGE Less equal than Value range - + filter.parameter_value_constraint.operator.RANGE_IN_RANGE Range is completly in Value range - + filter.parameter_value_constraint.operator.RANGE_INTERSECT_RANGE Range intersects Value range - + filter.text_constraint.value No value set - + filter.number_constraint.value1 No value set - + filter.number_constraint.value2 Maximum value - + filter.datetime_constraint.value1 No datetime set - + filter.datetime_constraint.value2 Maximum datetime - + filter.constraint.add Add constraint - + part.filter.parameters_count Number of parameters - + part.filter.lotDescription Lot description - + parts_list.search.searching_for - Searching parts with keyword <b>%keyword%</b> + %keyword%]]> - + parts_list.search_options.caption Enabled search options - + attachment.table.element_type Associated element type - + log.level.debug Debug - + log.level.info Info - + log.level.notice Notice - + log.level.warning Warning - + log.level.error Error - + log.level.critical Critical - + log.level.alert Alert - + log.level.emergency Emergency - + log.type.security Security related event - + log.type.instock_changed [LEGACY] Instock changed - + device_part.label Device part - + log.target_id Target element ID - - + + entity.info.parts_count_recursive Number of parts with this element or its subelements + + + tools.server_infos.title + Server Infos + + + + + permission.preset.read_only + Read-Only + + + + + permission.preset.read_only.desc + Only allow read operations on data + + + + + permission.preset.all_inherit + Inherit all + + + + + permission.preset.all_inherit.desc + Set all permissions to Inherit + + + + + permission.preset.all_forbid + Forbid all + + + + + permission.preset.all_forbid.desc + Set all permissions to Forbid + + + + + permission.preset.all_allow + Allow all + + + + + permission.preset.all_allow.desc + Set all permissions to allow + + + + + perm.server_infos + Server infos + + + + + permission.preset.editor + Editor + + + + + permission.preset.editor.desc + Allow to change parts and data structures + + + + + permission.preset.admin + Admin + + + + + permission.preset.admin.desc + Allow administrative actions + + + + + permission.preset.button + Apply preset + + + + + perm.attachments.show_private + Show private attachments + + + + + perm.attachments.list_attachments + Show list of all attachments + + + + + user.edit.permission_success + Permission preset applied successfully. Check if the new permissions fit your needs. + + + + + perm.group.data + Data + + diff --git a/translations/security.en.xlf b/translations/security.en.xlf new file mode 100644 index 00000000..8c76136f --- /dev/null +++ b/translations/security.en.xlf @@ -0,0 +1,11 @@ + + + + + + user.login_error.user_disabled + Your account is disabled! Contact an administrator if you think this is wrong. + + + + diff --git a/yarn.lock b/yarn.lock index 6c378a12..9e6e8e17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -901,59 +901,59 @@ to-fast-properties "^2.0.0" "@ckeditor/ckeditor5-alignment@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-35.3.0.tgz#47dfb938c0827837220fd54e2fddb72106a60b2b" - integrity sha512-j/6GrvPtaEJlx3T3rAh2oFoBz3mLQqgNql0c1jWNXwRapBVaXGDCbQVKbnGs1ESbArY4BUNZU/QIxHF/4slfOw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-alignment/-/ckeditor5-alignment-35.3.2.tgz#223c8c275b2ab395b7ce6eff94c83eb42512d647" + integrity sha512-/j3WmRkfJ/v1fb8aKj4+YJagn6g9CeFNmUwPFVXYiLs1KPIoP+cH3k25teW5Xx69WOWObrgZ+H4n7TpLsxa4Uw== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-autoformat@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-35.3.0.tgz#1ccdbb38c42e2567c7c802ab412d553f7a84aa6b" - integrity sha512-jtSUCje75gKSI7QD/NNuLNFufPxBVaMd17IDQCGvVvllFHsYScfiewRuq7DuLdZQfcHbtF6jMhExF/gvJ572VQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-autoformat/-/ckeditor5-autoformat-35.3.2.tgz#db42c4b14a22a3728968eadc7f4431e4c4deba43" + integrity sha512-ZSL2JfbAITu6BKbQBxNf0YEFcx5d94JcvbiuZiEhDf/W9GjLQ/M1RgWo9/5ze1qEDBPwa4euf2xX6d3kDIINag== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-basic-styles@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-35.3.0.tgz#f6424ac51b1b1399fff385d65cf31c72487d1756" - integrity sha512-tEqD61vcU33XOt+KaRE6qZqNaG4VN8O7vgEx4sA6OOgx+bFu6D21Djt8V1WV/+HmQ9ssl5oLmYmP7Or4RrXzgg== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-basic-styles/-/ckeditor5-basic-styles-35.3.2.tgz#0c0df61cabaedf5fe3a7a39ee12b32a97b64f311" + integrity sha512-AIB94555CxlZDCpATYzF3o+Jvx4Wm/OVbMT4Z1TCcoRHS0AjmCR2ZaeQvw+RCoNhYim+O0oQwgDwfkjJsaXNCw== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-block-quote@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-35.3.0.tgz#fdf179b0c0dcf37c16170191ecdea457b173fb91" - integrity sha512-iBBTwRJihX0/rj1C9jfrJ9drCYvcuj5q9BZ435z/XR0emQkOsNWq4aayUtKBuZedjn+B0jhNfF7lVTdxgYuRKA== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-block-quote/-/ckeditor5-block-quote-35.3.2.tgz#1ed95c0b71bbabe62cae52013fcdddc26191b40d" + integrity sha512-6hBQ5+ltGxuYfg6mKjbk9PoHHkLAFAy7xCxQA9UeCD8rVI//ELTfTQAY/VBhzdNE6vhcSrnrxajZCFxANLTFrQ== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" -"@ckeditor/ckeditor5-clipboard@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-35.3.0.tgz#7a594498d315ae64bcee69e69d6664094623204c" - integrity sha512-4bdMY4FvFSVe3LduZw2nPyoD40tTUl4MxX/iumtuvzt1Vk6fp2CTswbsv7VJaKVmTE79G7a4giI3ijI+SLyDmg== +"@ckeditor/ckeditor5-clipboard@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-35.3.2.tgz#7428827a098498347995259c12a03850bf9e1cb0" + integrity sha512-0l+dN8CrAHMC085mohVfolhOdGLvwky6HoYoAlxPMe8n3zCFgQtlcolmj3cA8qrO7OvFDSl2YrtWfg8mb+BeSA== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" - "@ckeditor/ckeditor5-widget" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" + "@ckeditor/ckeditor5-widget" "^35.3.2" lodash-es "^4.17.11" "@ckeditor/ckeditor5-code-block@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-35.3.0.tgz#5d246453d635f7ee3966453fd402062400ee87a0" - integrity sha512-JT8u64vQSB9G4Ad8lg2FrIx5f929IwQ8mqEu1pJc+Ea9SpJYGtTSJP23PokPtl1Tt20/l6LHW45XmV34JfnPRw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-code-block/-/ckeditor5-code-block-35.3.2.tgz#41f90f30ec35c584256035d857e949291c9ad5b8" + integrity sha512-ir6LoZeQVF3KbvumMj/pl7p2nyVe6DCbRHHcFR1ChoTbFCNJ5O8tnB3iFS8vrgP/zoVR6JEqyIVYtTtVTLTKOA== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" -"@ckeditor/ckeditor5-core@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-35.3.0.tgz#cf595976217af4344d80c7cff3b8191c2a1c1bf2" - integrity sha512-LK6G9tZkGXFeb21fXZTgu1Usq3ICOACPeSW9L7EfDA1hUroXjkTwsq7aPAvi9+0kZfYWO11sG2nxGdRX5gg2XA== +"@ckeditor/ckeditor5-core@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-35.3.2.tgz#0c8efda8f3f998fa5170bedc16b346b516b856e8" + integrity sha512-OnrHf9i0D79DdIMIE98A9x0y4XCxGItcOXcTHd9s+jWFMtiAvQ37vDGrqgDlHW646RBBF0GAmxrmP4F9HzEeMA== dependencies: - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-dev-utils@^30.3.1", "@ckeditor/ckeditor5-dev-utils@^30.5.0": @@ -998,272 +998,272 @@ webpack-sources "^2.0.1" "@ckeditor/ckeditor5-editor-classic@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-35.3.0.tgz#ec47b29977e6af1c263d2d9ee0ba1da316c177ed" - integrity sha512-nTlqNL+JtTOCkm60E9TjpB4c7bJFUC12r7ehc32lbgMQKKTY+NhikaRG8rmL/zSi5D9AfLA7JpocvDzxd5wj1Q== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-editor-classic/-/ckeditor5-editor-classic-35.3.2.tgz#f6b3638c887f61303bdeb87831dfe77d332d1eea" + integrity sha512-30rMzfTp3oMwmj4aDiDmISF0nTO4IVKp0yKvMDUfUCSTGGWBpOoCycBQbNLUG0Dn7ExUUHz6v9Wo07Efki3IYQ== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" -"@ckeditor/ckeditor5-engine@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-35.3.0.tgz#1dcdde6a38970b9642cd5c2e0900fd6eb39c72b9" - integrity sha512-7vQLl66k0mv0UIjwXKmqidyIt5FDabKTOzwES+8hYVvYTW+pVkM5Y72ZHmo0OIVLj1oaQo15sLxlquSjUTbPWA== +"@ckeditor/ckeditor5-engine@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-35.3.2.tgz#1f3d45a71670b0b85087d04d17e72f88bcd6761f" + integrity sha512-/H20Y6VlYxRyNiorRXF3VtbykQqgo+RbhMfzRQasC9TdrFyRaC3HW67Kq5bjeKoeoZweEM6Dziy8pnrMZlhecg== dependencies: - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-utils" "^35.3.2" lodash-es "^4.17.15" -"@ckeditor/ckeditor5-enter@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-35.3.0.tgz#a84610f6f48206e99c3f5565973e583d9efdacb2" - integrity sha512-bPikoNAoFhN2Nh/NHTq46VQu0n7+pFnYSgRcR/Vlp/1DoXi7L5z1Qrcm/W5WUvwMXEFT2C0llJoaFA0OJv1a1w== +"@ckeditor/ckeditor5-enter@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-35.3.2.tgz#0109817aca29d6c18a180bd663240985e0ac2f4a" + integrity sha512-9bm4TbyIUu880FFVkNRUqSOYOs5R37CIB8BQZqV2T7cOI7L4RT0+hyXu+Zmg844WSD/+GtAZ+y0FlSi50Ze6oA== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" "@ckeditor/ckeditor5-essentials@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-35.3.0.tgz#bbe647e2c18bdd5f24c41075efca2ad650c00bdc" - integrity sha512-wXTssnSQgzcjPLFqqZ1tokwZptz20/UTyD/JPITIm4gj+iVXTw9Ga9ofAc4z5E7+oKplxhPA341sgQv8vSrTNg== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-essentials/-/ckeditor5-essentials-35.3.2.tgz#d4cb0ffbc3f22bc9cff545d0053f5ac049e270d3" + integrity sha512-zgVqqkq+747mdYPEuQoH8xmNVmPv6sdcz5B8WBWFYrjriD4kvQIfD611osJ2k8Y2hNozpzAXXYPiZOa1UKPJ+w== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-find-and-replace@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-35.3.0.tgz#adabc73e8ed728375177398138e84aa56707150b" - integrity sha512-eDL7dBfn+mXPG0IDki+4JYgXlY7pG6Rp3K/Q4Gxs3B3/px2BzC+iASzhE6CO22XM7uOMn/+I/0YquDZa6q7/Xw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-find-and-replace/-/ckeditor5-find-and-replace-35.3.2.tgz#64f5d9193faef4479fa2cc263a2dc11227af7826" + integrity sha512-pZ9mTXDHnC/OFCprvEHKZzW1aWlcFbAZGso/l7WwMeMO8tfuyMBI7c0njYd6z8arnSn1og+F2rpaQngMbJnAHQ== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-font@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-35.3.0.tgz#5e2be3f0236118d881baa0826183fd73709c68cd" - integrity sha512-KGrSY+A1gKtTori6sUZosJPUA1dFnPQO4XMFlPsupuOTe8tiiCRwKIcFnSUShEUsiYM9LQMn6MZ8HHl1clgpYg== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-font/-/ckeditor5-font-35.3.2.tgz#daff8f9fe4ba8cdf1b37e60e27116efa4f110422" + integrity sha512-j9CbD6ImOhb2K7HUEsJoSD2e7lBUZTdQS++6H5AqigmjH+EQZwuMJKjlodzK9OldV7U2mqs0C/qrph5sDEJSYQ== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-heading@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-35.3.0.tgz#8ebcac4262a6b96a4e6f2c8e50389e789aae1be8" - integrity sha512-YFJtsax9UV3HmjexOBdhWuxubwPH+RCTC5j0OeCaj1gsGr4DMAJrs2ofmO1Voe9zIbCStoZP6cmIGZZ/ga2QNQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-heading/-/ckeditor5-heading-35.3.2.tgz#74a7ed138babac6961812d750d8e17584a7e2fa3" + integrity sha512-cJ9iL875yd8kQ7XlzcrT1qP4RZBgkydhWT7ERVJtctvHBVARd0rOpzpax3w2eCVwufO0fQcjh154u3IHREKb/w== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-highlight@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-35.3.0.tgz#7f8b59a181bda3faaece40fc68eb03ff4e0f9233" - integrity sha512-AB8hg5ga2HyrLqb9/Bw6HUQjN+gj2cR7N6zT1DYs0awYPNVYK+JKE0L9bMuEAyVLlHpyILFxqw5a35YS+8HmbA== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-highlight/-/ckeditor5-highlight-35.3.2.tgz#f418e9f0eaabf83b9f8fc3a7eb9a8ef674762517" + integrity sha512-RNlIEuV/yRgUgBSCzxcJ9pw42g5iX4QKQCFQlYg/PkhqgrOU4Q1iAvHQWUXHq8xsS8QX0Lv1YGJTe3bw3K9i4Q== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-horizontal-line@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-35.3.0.tgz#3de7ec77cea7abcc2d3b8211a5ff22e69f255fd6" - integrity sha512-eNlBZxOLAV5hz0YzG5ozuInCqMVqVKOvFdA30EH8vnwjq3ehfvOYTHsRLJZbBiCw515X+Gy+3Avo1E2aoR6PeQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-horizontal-line/-/ckeditor5-horizontal-line-35.3.2.tgz#91a6a87a67cec9093062393d43ead894e30f8922" + integrity sha512-Ons9O3Tp6tjuI5jfT6Z3Ckb+wWesMlRl4xWcJ817mZI+qWPzLX8MkFPeOmguZERK2YtA2CjVxrlftvysob7qcw== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-html-embed@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-35.3.0.tgz#1ee5c1b2c5310b0fc627ea61061e662d39f3a4dd" - integrity sha512-4K82puSKNKmwQ+Ma+8pMjoLVmHTwx7bcE+nHNB7+BstIimLcA44nqGcC46mrUYYlF3O6nlYbiNGwgGNEWm/UJw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-embed/-/ckeditor5-html-embed-35.3.2.tgz#72d164a560e7a34d5704352ff3ae9042d9b13615" + integrity sha512-wj5gH2bZB0uLrEEh/MJ17xSAUNaW8XnQ0AtOuOUG68L5ynqyarC6RnulgYccD52hGYNmDo/E11WxdrESnhi1dg== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-html-support@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-35.3.0.tgz#fe57f289e6666b58694cc58e38a7cfa529346983" - integrity sha512-VPQkMDXMCHJ1G9AW2UzX17AUf03h+KCSyzteZhyb6z7mV542Z+yZ0rG8MnRu12z3vwbKNHScXxPTRW6XAI325Q== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-html-support/-/ckeditor5-html-support-35.3.2.tgz#4db535e54b79913f70801a209e53bb339a79b1d5" + integrity sha512-SZNg3OSqDsuV+YcfiFzUCMzkVkVuVhqzzErXYiA/uZf8SV3P68o+vQ98R9kBx6Xp9Gk4ifUz0eWYv1kmMK4K/Q== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-image@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-35.3.0.tgz#54f86461c03afad1e47c6b5ebe15eac4fa16c14d" - integrity sha512-9Va5LSh0G7ixGbWSZOofP9zIWJDCNeSJPXHYiiGkAjRARn92Z/wNCa5znWmIiJJxLmOiG/2gqSUNvPyE1LJ0oQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-image/-/ckeditor5-image-35.3.2.tgz#f68cbf10d894e2a54352a40bad853c14bf217b91" + integrity sha512-9rTVH3rZviXNgXCkutMg9Td6i9DIInp8JaRlNBOuIMc0iEjD+VEAIZ4eUMIMXeTeXF5jyNMcqbTSK/DwN1LAgg== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-indent@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-35.3.0.tgz#d429c12c5ffa8ff39a5056026c8a6e9e984bb1ef" - integrity sha512-rMPD/z4nbfTd4oL07/2D1wVF4GI+maOmgHmVzeqcxCL8w3/7cz4/ShA883YINnVF5yE82TbH+8FE7P2Ok2U0QQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-indent/-/ckeditor5-indent-35.3.2.tgz#4dea269c3db0da09ac744b2294b00da3a14bfb40" + integrity sha512-0oiaDLcNTWVt8lXJFi25rZqKe/VQ4ZULeNc/mgm6W17N+3Ua0uAqORFVEJcccn6QDwmiyMP9LJp2k59e1VE97A== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-link@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-35.3.0.tgz#4bff3e209d51acca8096c5f229f7218f62e91df8" - integrity sha512-2y62z/JZmRADb/5eYcbhWLN6OtKURoL/C1Rn/u0rfDFHPFEC98ZW07uVJnIYN1KyohXqkCg/+8JzB5y03UoWUw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-link/-/ckeditor5-link-35.3.2.tgz#77d8effdd08a3cd70d59229c82e3e16bb1d10c62" + integrity sha512-NM44sefnoHeXyUAETHgP4TywLWlSnS2HQaxSHF74EhB3sDNRE+GXiY8DHRd+pMWHvGksOhz9OJMgMIl8wnsRvQ== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-list@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-35.3.0.tgz#44175335ddf76d93d35e889d18428803fca5cfa3" - integrity sha512-UFw6AP+EVHuC4Xr5zkcQO9a3ndSD+2FdFr1rSi2V/f2iz+Il1LQPol8lKbRXkR1K5C2Bw7vR6d/1QnNkBSFzgQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-list/-/ckeditor5-list-35.3.2.tgz#4218e1e3ee7133ba8b8b99973eea5f0af303ac01" + integrity sha512-PQ6DoINXkefhboEPF92TdjebItvza6dXemIbDwEwC9RhXL73IEsiqnTB5ThHobKNXhZJo+gGBlVHD2WzKMUwiQ== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-markdown-gfm@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-35.3.0.tgz#2dae7a8c97aea7e6660ef1a423264f40346fcf8a" - integrity sha512-UDljcnOL3zP6OVnxPpDH1MnQxPvoj6OX0Wxn7AjYfgWJgdcftPbPgIdMH9PCA2bXHcTcQrx1jkJfH/wZzeOz1Q== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-markdown-gfm/-/ckeditor5-markdown-gfm-35.3.2.tgz#13ce69bf7ba336b84b93f93eea077635b2ab37b5" + integrity sha512-8+xXSLA2WJIdUCFQLei1QG0tW+85oA/evgSGnTWSG+RHOGOuF6DxElYpA6S/V1brX0uFAMzHKzMH4hL74IvAVA== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" marked "4.0.12" turndown "^6.0.0" turndown-plugin-gfm "^1.0.2" "@ckeditor/ckeditor5-media-embed@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-35.3.0.tgz#52179e0c13fdb94210496933cf6d0bfdfbce8146" - integrity sha512-1lud4nNwC8/801/8xBg519JgLKh34xGFC0ultrHTAZGIjAEfcZN+e06eThoEjRsznZaFFOn/dM874pTyZk4Eig== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-media-embed/-/ckeditor5-media-embed-35.3.2.tgz#cc6c069377ef72dcbde82220a351f24af618b9d9" + integrity sha512-2dHD0hYFOAp9DW3OE68wWFrmvZkI8cBzpYkSWmMzhRnRBzh/RMQCgKXjriYw5eCRX8pDnpjdRD0Wmi8a1BABAw== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" + ckeditor5 "^35.3.2" -"@ckeditor/ckeditor5-paragraph@^35.0.0", "@ckeditor/ckeditor5-paragraph@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-35.3.0.tgz#e7d47db5fc5489562d5f10a48db2f1d03223b578" - integrity sha512-7NRQTbEZvXLOtHRZ+xo3NRm9OCJ50BkhgIw6O4HlvQqlvwu82vx5F/ROmhvFLiCJZX8FdDP9MdBmzgEqRIpmPw== +"@ckeditor/ckeditor5-paragraph@^35.0.0", "@ckeditor/ckeditor5-paragraph@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-35.3.2.tgz#22e7c1f44fc293eea110288370127082827231f5" + integrity sha512-1t0cEio8fW28pSw1J2kFKH6N7aiwx7H9NQ+GSfCufeSZcI/PUs+oWfehLcNswrdD4M77o+AZrc3BYrmxQYSLOw== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" "@ckeditor/ckeditor5-paste-from-office@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-35.3.0.tgz#431a4563b827f2d649d6dd3a7b8704134d7f7490" - integrity sha512-JLz6IFMRW1fyrTW8o8WdNJWhrfgD3NEqqi3aLWe47osymHvaTAIce+n2vRP/pDstaMOhiLGolfVg7O39dnEm9w== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paste-from-office/-/ckeditor5-paste-from-office-35.3.2.tgz#6336f80047bfb2ff573fa11a77aaf3e98bec589c" + integrity sha512-CHmhw9/deTS3o+4NqIEL41Yd2WXqP3z4VYR4DHZGK6iI2DKTrLcHU/ofz8fQHnU/7JqtiiZpPlZLnGRr3Yq6+Q== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-remove-format@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-35.3.0.tgz#c74838793aefb30ff33c00894cbe7c1a0cd1db8e" - integrity sha512-6MYwRbQTEFi88idltnu42ninHtnjiJAbrZfK9aoyJHlFk+Kjdu6rrwPqcK5d9amasIlm/bNkU/J+WU55vFmf0g== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-remove-format/-/ckeditor5-remove-format-35.3.2.tgz#f2af335238884bf945f77ac375c13d501a28a076" + integrity sha512-Izvyogfq/QUbE6I1Y4qA6qlhP6x40sFdpRhsFWx6ynPTgvR4id+b4GfbQ2Od+ETje32kmghJGlXoUMpn5uaCyg== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" -"@ckeditor/ckeditor5-select-all@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-35.3.0.tgz#8b51296bf151ef38c6088dd08b5a4ccc17ada02b" - integrity sha512-1cjvI1BQ7g8n5TGtMKpcA1TGASxPnIT77BRYuZ89eDIWjxOevrsVtNo1H4dpQYY4cjNnLwtfNY3AprW8aYZQJQ== +"@ckeditor/ckeditor5-select-all@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-35.3.2.tgz#19aa0f25cad35c01cb5c4e0d8158c937fff4cbbc" + integrity sha512-MFfYGmXL1myexvXJyiFWI2eieEP2UcAmtyTE3NnFd3xV8dSVd59NRKT0gMQJFjVU/zflQCmNOqYYTGxpg7CROQ== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" "@ckeditor/ckeditor5-source-editing@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-35.3.0.tgz#6a575b08d981da430ecf586a8cfed509b7b5e972" - integrity sha512-QwE+c/J59evqvBe/INOiQ7kox4xg4QKpGMZDqXFd3jzqsxhlgM0esZVFB8ra1koGcE0QnTebdIWzfmrGnkwwWg== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-source-editing/-/ckeditor5-source-editing-35.3.2.tgz#b5f996b7bc1548e275d704dbc80afaf4684e4398" + integrity sha512-dmzIIa6LykDsT8VLinSpyyWo/lBOQqi128IuuUHeQhAHrQFpYr2pCu/lkr9azlcK5xRvPC0tE1Wy8rQNS0X4aA== dependencies: - "@ckeditor/ckeditor5-theme-lark" "^35.3.0" - ckeditor5 "^35.3.0" + "@ckeditor/ckeditor5-theme-lark" "^35.3.2" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-special-characters@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-35.3.0.tgz#4ac214a0f4a6e3340506dbb30a0572a6e8ab05ba" - integrity sha512-kaJB+touKPQKOEOh1XpcN1Y8Du36kSh2B/z8QEwLXXb23x++ry286kOYDRoijc2xu11PVkspJ8eNjgvgnpbvLw== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-special-characters/-/ckeditor5-special-characters-35.3.2.tgz#7bd4e59d09f64a0d9e0c2242584f24e53d57aac1" + integrity sha512-FMGqTeBMjENGTyfTF+ESwUZSFc5rYokGWrJXBgBeDFUH+gSY0m3WM+ZBWfjLW14ZTXbP5NeirdifojFpmHITwA== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" "@ckeditor/ckeditor5-table@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-35.3.0.tgz#a7a9989895aa602c62faf4d1ab5c062c8b804cbe" - integrity sha512-qMCQ4RlrQyedzJGHR2QnHtqxqzHj7wxt8yxz5hmS6tt2vcn6yQKvKE3PMyYTEp6Zz3VUtIw+jCEMPmB0Q23elA== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-table/-/ckeditor5-table-35.3.2.tgz#daab88c10507e3838a6c5421cf65000206ba0860" + integrity sha512-BFY8NL6QBYQMjEWwtwTZSeE7QEfrTgbSAP7Ndxh+SshEgGNbH4D6ZaiC1A1OYb/ABqe+g7LXpG/O+2nGM9YkxA== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" -"@ckeditor/ckeditor5-theme-lark@^35.0.0", "@ckeditor/ckeditor5-theme-lark@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-35.3.0.tgz#b06e2f48d6b33f9a6f840991fcb2c5e967d3f54b" - integrity sha512-c/ejug43nkE21Qa59qkAOAAUKWi7uBcsEIxBCWNFC24V/bvnbCgeHk7R+fOYgKzQ1tGndFcfN1V50AiIW0YpLA== +"@ckeditor/ckeditor5-theme-lark@^35.0.0", "@ckeditor/ckeditor5-theme-lark@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-theme-lark/-/ckeditor5-theme-lark-35.3.2.tgz#0b84e3960b37456d4a2d7497ff60540e90d1b631" + integrity sha512-3YZXJXUnX90A9Ju4fth9zVki2yDhTGRCCzZGKseM7BdJU7Drc8caQh5vTKjN8g9t4xZKCPsGPaeZ2Jk5Wd1f3Q== dependencies: - "@ckeditor/ckeditor5-ui" "^35.3.0" + "@ckeditor/ckeditor5-ui" "^35.3.2" -"@ckeditor/ckeditor5-typing@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-35.3.0.tgz#143af2516caf3595072bd11debd8762f29696a2b" - integrity sha512-ZY3UHVVq92Z2lVdgKuWbWC0blg+k3i+Np/DE44gDCFPiXPk0Fl2JK0wmtc3HYAvcn1IAgaMYwsEglFO4SHSnNQ== +"@ckeditor/ckeditor5-typing@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-35.3.2.tgz#6735a9ac62caa671fde33d1cfc4ba90f23ca6da2" + integrity sha512-cu5gSAKGHAUdKVA1p8NBppoBuQSbDFdTaBFE51ske+RQhFpMBQVyHzgxfsXb/Ui7f3fDw91eJLg8MtrChvDPsA== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" lodash-es "^4.17.15" -"@ckeditor/ckeditor5-ui@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-35.3.0.tgz#1b61568c02757406dabce21824be816462ac7446" - integrity sha512-8RQJUSdVJTx8/PxHRHU8mbnJCZJ4BblWVDirtvLfzqGn+ECnM8wa1mQM2OvFTjS+rkvhVL2FkdXTw8Qy7oltKA== +"@ckeditor/ckeditor5-ui@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-35.3.2.tgz#bf5d84541066064e7a2c9164bc8f85e04b395214" + integrity sha512-0NlDVRsC9H9dx9I54reolXp2O/4a31aV7vhubiIzVVNiHkOxzfUSNnzhOzeMP7pej6ZYt/jTqCtv0qy+35ByOQ== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" lodash-es "^4.17.15" -"@ckeditor/ckeditor5-undo@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-35.3.0.tgz#e26c87db67b19f4ec81d14a62093d6b8eabde9ce" - integrity sha512-Ma423T/zZxlOVLDzKgti+Lfuc+l64UkahAarn2Hph85d4oV+u94NRcLQkwQczk9iQ1fUyC6SL/KpELo1kQWZsA== +"@ckeditor/ckeditor5-undo@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-35.3.2.tgz#d5781c82d017fa58b55c5c893814a12a801633c6" + integrity sha512-1vjIytAE/VhCGrN3IrhEJHURrPHYxtBzUEgDWPwvGZhML8vG9+4PtEvfUF3+rDiI5c6CkcJ77phPIM6KM9z4ow== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" -"@ckeditor/ckeditor5-upload@^35.0.0", "@ckeditor/ckeditor5-upload@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-35.3.0.tgz#d4ba17fd47160451541fbc9bb11386dcec49b48e" - integrity sha512-AniyS3PtO0e47CjLFOlSL97ddxVdM40xgDZ/3QWQfZkUn5oPJeuBu6tRhCDEJHQFk3cPY7mK0TC4ozUu/KSR6Q== +"@ckeditor/ckeditor5-upload@^35.0.0", "@ckeditor/ckeditor5-upload@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-35.3.2.tgz#347fe95165b3ccb53a47bc5d35255e4b3a03a136" + integrity sha512-/xq5foAuf+3xWDlzm3qLloEAVVYGlJ92LFyrMSmw3Kzu8Cu/yQR8wRscgXLQWa1MpzasYLl09N0hxBi9evtx7Q== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" -"@ckeditor/ckeditor5-utils@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-35.3.0.tgz#ee465fc5c97a377e793219790307a4401c68541a" - integrity sha512-kS6CsTbyDlSnWRUytH7c8rCkVRmO5ZXCX+uJIOYpa+CvKoVCECdfHKx3w5PmsYgRvbbnX+kVtaI5e5ujRCknfA== +"@ckeditor/ckeditor5-utils@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-35.3.2.tgz#2366c9bbb22a082c792371d79dd9821247812b01" + integrity sha512-iw2361Ek9K8Dqu8JI60DcijSsDzHMZVCNiwxBCxDEywmEKod5hENwnwZvQM+C0CWBmshQCAXhy/dJ1YWTvGrsg== dependencies: lodash-es "^4.17.15" "@ckeditor/ckeditor5-watchdog@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-35.3.0.tgz#5bbaa7eadc12060b1482d950893a20e0bcb3befc" - integrity sha512-dfMFkd4rGoF0dihuyXjuti46wX3qrewGyOasFxgB/YzKU2lO2SEg/pDQHsbBuQO90XnwJrF+yo83IzAUTxqdNQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-watchdog/-/ckeditor5-watchdog-35.3.2.tgz#1be058fe02a4afb98e1ab6794312a7be469b7db5" + integrity sha512-c2s2poWKpA+5J3qXh5MUdR9aXTZIqU+sLVPlMvZvKTJkXNR9g4IjYz4q4Agw5u2QVitraEkIm/War1Y8JQB+cA== dependencies: lodash-es "^4.17.15" -"@ckeditor/ckeditor5-widget@^35.3.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-35.3.0.tgz#50d3e240f030d7a266f927b59b3c06fc95c4321e" - integrity sha512-KBqEHtrCgb9QOirCJKLUjnMVSiYMq8yGFbczKyZd/XdPFTWo8HuBm0i+A1eONrhIP8pFiTsBgsSizsoII0h5Ww== +"@ckeditor/ckeditor5-widget@^35.3.2": + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-35.3.2.tgz#c6dc031a2ae506c5ab5eb47119d5c515f56ae4bb" + integrity sha512-68T4X6hx9wKC8W5FZ1fcREFQu3O5GDRECZjSZ7xpPZU42ahzeolRVmGFeeRVl2ZgMMVp1YdE2tU4rXFQ8Uwk7Q== dependencies: - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-enter" "^35.3.0" - "@ckeditor/ckeditor5-typing" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-enter" "^35.3.2" + "@ckeditor/ckeditor5-typing" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" lodash-es "^4.17.15" "@ckeditor/ckeditor5-word-count@^35.0.0": - version "35.3.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-35.3.0.tgz#1bd1798f60c7594cb438d73662ed05c3b30236b9" - integrity sha512-u9YPWFx6ZMAk7alc0RY6xotAJBqL4MnO6I3mGGHMAjvNVxkWnrOesDuIxfMBef9Qu5/8YBV95bP6scAa/TJhuQ== + version "35.3.2" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-word-count/-/ckeditor5-word-count-35.3.2.tgz#2de789d2495d04903fdc2747dd717c7c6204769c" + integrity sha512-ZpPf3lSlLtudVxbpsM+d/TCoffbKemn0kJqQtaZUQHWXn7ig82QgpMVugyDzGsRsfPiK4HA37qKMegun1d+Svw== dependencies: - ckeditor5 "^35.3.0" + ckeditor5 "^35.3.2" lodash-es "^4.17.15" "@csstools/selector-specificity@^2.0.0": @@ -1317,9 +1317,9 @@ integrity sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA== "@fortawesome/fontawesome-free@^6.1.1": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz#ba3510825b332816fe7190f28827f8cb33a298b5" - integrity sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz#344baf6ff9eaad7a73cff067d8c56bfc11ae5304" + integrity sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A== "@gar/promisify@^1.0.1": version "1.1.3" @@ -1507,9 +1507,9 @@ version "0.1.0" "@symfony/webpack-encore@^4.1.0": - version "4.1.1" - resolved "https://registry.yarnpkg.com/@symfony/webpack-encore/-/webpack-encore-4.1.1.tgz#6cf86d5438378f076136ddedbae132e3d82a0280" - integrity sha512-uZRXej1prTvYG/QJWR/DzKcZtBKEXDkGtK9qlQtO43ip8t8NIZmM+w8qeb4eiS7aoULWmpG7GpQOLWPhsccUDA== + version "4.1.2" + resolved "https://registry.yarnpkg.com/@symfony/webpack-encore/-/webpack-encore-4.1.2.tgz#152c21bba61c44001b739e2ad3054dc0ddcc0afe" + integrity sha512-qODQon/RCFlpB/OYrFdNL+FmSbJvfrFRrTQ8a3czIA9NiJ85a5CjWFXVs+ri4Dy/X/aEUcMmjBYkgxbGlB1xwQ== dependencies: "@nuxt/friendly-errors-webpack-plugin" "^2.5.1" assets-webpack-plugin "7.0.*" @@ -1731,9 +1731,9 @@ integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^17.0.8": - version "17.0.13" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.13.tgz#34cced675ca1b1d51fcf4d34c3c6f0fa142a5c76" - integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg== + version "17.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.14.tgz#0943473052c24bd8cf2d1de25f1a710259327237" + integrity sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw== dependencies: "@types/yargs-parser" "*" @@ -1993,9 +1993,9 @@ ajv@^6.12.4, ajv@^6.12.5: uri-js "^4.2.2" ajv@^8.0.0, ajv@^8.8.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + version "8.11.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.2.tgz#aecb20b50607acf2569b6382167b65a96008bb78" + integrity sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -2032,9 +2032,9 @@ ansi-styles@^4.1.0: color-convert "^2.0.1" anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -2207,9 +2207,9 @@ bootstrap-select@v1.14.0-beta3: integrity sha512-wYUDY4NAYBcNydXybE7wh3+ucyf+AcUOhZ+e0TFIoZ38A+k/3BVT1RPl5f0CiPxAexP1IQuqALKMqI8wtZS71A== bootstrap@^5.1.3: - version "5.2.2" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.2.tgz#834e053eed584a65e244d8aa112a6959f56e27a0" - integrity sha512-dEtzMTV71n6Fhmbg4fYJzQsw1N29hJKO1js5ackCgIpDcGid2ETMGC6zwSYw09v05Y+oRdQ9loC54zB1La3hHQ== + version "5.2.3" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.3.tgz#54739f4414de121b9785c5da3c87b37ff008322b" + integrity sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ== bootswatch@^5.1.3: version "5.2.2" @@ -2362,9 +2362,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400: - version "1.0.30001431" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz#e7c59bd1bc518fae03a4656be442ce6c4887a795" - integrity sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ== + version "1.0.30001434" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz#ec1ec1cfb0a93a34a0600d37903853030520a4e5" + integrity sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA== chalk@^2.0.0, chalk@^2.3.2: version "2.4.2" @@ -2417,27 +2417,27 @@ chrome-trace-event@^1.0.2: integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^3.2.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.5.0.tgz#bfac2a29263de4c829d806b1ab478e35091e171f" - integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw== + version "3.7.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.0.tgz#6d01b3696c59915b6ce057e4aa4adfc2fa25f5ef" + integrity sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog== -ckeditor5@^35.3.0: - version "35.3.0" - resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-35.3.0.tgz#957b717217c524d32f9f18e6e0df5128d0e8b25b" - integrity sha512-37/BmyZbBG29PZuZIhnQ6ju6LEPuD0ptNjXQzxTwkcUBS9cSaDN4r3p+xVdXrOYIF5mKUZrSGKA0/wyo0j6p0w== +ckeditor5@^35.3.2: + version "35.3.2" + resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-35.3.2.tgz#c5cf786fd09b439fa5b1639b79467f2744d39124" + integrity sha512-QQbXi3EbarHOdb8qgQ+EY8PhDYrtpRMQC3k3J9rhTZLQcVYYxMkFwlVtaN8TtxpLo00KGAV1+FticdBL7RqpXA== dependencies: - "@ckeditor/ckeditor5-clipboard" "^35.3.0" - "@ckeditor/ckeditor5-core" "^35.3.0" - "@ckeditor/ckeditor5-engine" "^35.3.0" - "@ckeditor/ckeditor5-enter" "^35.3.0" - "@ckeditor/ckeditor5-paragraph" "^35.3.0" - "@ckeditor/ckeditor5-select-all" "^35.3.0" - "@ckeditor/ckeditor5-typing" "^35.3.0" - "@ckeditor/ckeditor5-ui" "^35.3.0" - "@ckeditor/ckeditor5-undo" "^35.3.0" - "@ckeditor/ckeditor5-upload" "^35.3.0" - "@ckeditor/ckeditor5-utils" "^35.3.0" - "@ckeditor/ckeditor5-widget" "^35.3.0" + "@ckeditor/ckeditor5-clipboard" "^35.3.2" + "@ckeditor/ckeditor5-core" "^35.3.2" + "@ckeditor/ckeditor5-engine" "^35.3.2" + "@ckeditor/ckeditor5-enter" "^35.3.2" + "@ckeditor/ckeditor5-paragraph" "^35.3.2" + "@ckeditor/ckeditor5-select-all" "^35.3.2" + "@ckeditor/ckeditor5-typing" "^35.3.2" + "@ckeditor/ckeditor5-ui" "^35.3.2" + "@ckeditor/ckeditor5-undo" "^35.3.2" + "@ckeditor/ckeditor5-upload" "^35.3.2" + "@ckeditor/ckeditor5-utils" "^35.3.2" + "@ckeditor/ckeditor5-widget" "^35.3.2" clean-stack@^2.0.0: version "2.2.0" @@ -2640,16 +2640,16 @@ copy-webpack-plugin@^11.0.0: serialize-javascript "^6.0.0" core-js-compat@^3.25.1: - version "3.26.0" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.0.tgz#94e2cf8ba3e63800c4956ea298a6473bc9d62b44" - integrity sha512-piOX9Go+Z4f9ZiBFLnZ5VrOpBl0h7IGCkiFUN11QTe6LjAvOT3ifL/5TdoizMh99hcGy5SoLyWbapIY/PIb/3A== + version "3.26.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.26.1.tgz#0e710b09ebf689d719545ac36e49041850f943df" + integrity sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A== dependencies: browserslist "^4.21.4" core-js@^3.23.0: - version "3.26.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.0.tgz#a516db0ed0811be10eac5d94f3b8463d03faccfe" - integrity sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw== + version "3.26.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e" + integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA== core-util-is@~1.0.0: version "1.0.3" @@ -2664,9 +2664,9 @@ corejs-typeahead@^1.2.1: jquery ">=1.11" cosmiconfig@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -2694,18 +2694,18 @@ css-declaration-sorter@^6.3.1: integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w== css-loader@^6.7.0: - version "6.7.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e" - integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw== + version "6.7.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.2.tgz#26bc22401b5921686a10fbeba75d124228302304" + integrity sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q== dependencies: icss-utils "^5.1.0" - postcss "^8.4.7" + postcss "^8.4.18" postcss-modules-extract-imports "^3.0.0" postcss-modules-local-by-default "^4.0.0" postcss-modules-scope "^3.0.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" - semver "^7.3.5" + semver "^7.3.8" css-minimizer-webpack-plugin@^4.0.0: version "4.2.2" @@ -2857,18 +2857,18 @@ datatables.net-bs5@>=1.12.1, datatables.net-bs5@^1.10.20: jquery ">=1.7" datatables.net-buttons-bs5@^2.2.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/datatables.net-buttons-bs5/-/datatables.net-buttons-bs5-2.3.2.tgz#a4c59729526f2f21a223ecf3140a67d46b2cf945" - integrity sha512-gakKYYeAj/Mq8XYXz4f9C667TvfvFN6+HlHHMu5OaarnzEvdJ1F8M2AHlZKH4K556E02PHChg5sMn2BiNIEeWw== + version "2.3.3" + resolved "https://registry.yarnpkg.com/datatables.net-buttons-bs5/-/datatables.net-buttons-bs5-2.3.3.tgz#6b59c24e17998a42c69d7b9f700458200494db35" + integrity sha512-SGixy5CPo2B2PJR9tKKVgLL2EUVHEt17dUlwPXKI1x0rxdFtzMhwW18dz1zeNSDgwTSgW1blkq088YboDOYUCg== dependencies: datatables.net-bs5 ">=1.12.1" datatables.net-buttons ">=2.2.3" jquery ">=1.7" datatables.net-buttons@>=2.2.3: - version "2.3.2" - resolved "https://registry.yarnpkg.com/datatables.net-buttons/-/datatables.net-buttons-2.3.2.tgz#1f64fa428d1ddc7a480b8bb0fb1fbb0f9ffc53b4" - integrity sha512-g0eH31sI0Q/Z8hWrlowUh1DzuBoMlnm/Odp2ZosYMvefd+XzL/B+99gHCmcDc3qO5agAbFvwKUInXy1Dk9Zc9Q== + version "2.3.3" + resolved "https://registry.yarnpkg.com/datatables.net-buttons/-/datatables.net-buttons-2.3.3.tgz#d54918ac82c681a0d58151d555ed690f40fef614" + integrity sha512-jK/hGF+NEj6CxDHKlpQiSu280G00VgL57SPyLbOA+DrmUd6wSGmdco0ztzYsbe9hzLJ3QnmB5LTpPPrBf8985Q== dependencies: datatables.net ">=1.12.1" jquery ">=1.7" @@ -3121,9 +3121,9 @@ domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: domelementtype "^2.2.0" dompurify@^2.0.6: - version "2.4.0" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.0.tgz#c9c88390f024c2823332615c9e20a453cf3825dd" - integrity sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA== + version "2.4.1" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.1.tgz#f9cb1a275fde9af6f2d0a2644ef648dd6847b631" + integrity sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA== domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" @@ -3177,9 +3177,9 @@ encodeurl@~1.0.2: integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" - integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== + version "5.12.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634" + integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -3790,9 +3790,9 @@ has@^1.0.1, has@^1.0.3: function-bind "^1.1.1" hotkeys-js@>=3: - version "3.10.0" - resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.10.0.tgz#2bbd13de4aa002fa916c34e3859239924311e35a" - integrity sha512-20xeVdOqcgTkMox0+BqFwADZP7+5dy/9CFPpAinSMh2d0s3b0Hs2V2D+lMh4Hphkf7VE9pwnOl58eP1te+REcg== + version "3.10.1" + resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.10.1.tgz#0c67e72298f235c9200e421ab112d156dc81356a" + integrity sha512-mshqjgTqx8ee0qryHvRgZaZDxTwxam/2yTQmQlqAWS3+twnq1jsY9Yng9zB7lWq6WRrjTbTOc7knNwccXQiAjQ== hpack.js@^2.1.6: version "2.1.6" @@ -3817,9 +3817,9 @@ html-entities@^2.3.2: integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== html5-qrcode@^2.2.1: - version "2.2.8" - resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.2.8.tgz#dbe8c98da2342faab27ee007f04ac22c88d7eeeb" - integrity sha512-Fvb7HmMmLex3xNXdzNfzLReiFw85ZuomALJTt8vB/Uu1ZFRGKw55kGc8j+APT08jJ28Kjr2SODHsrIJtPgvsQw== + version "2.3.3" + resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.3.tgz#e88fb2088e3475e22e2d938eb7e3df9b90d4ae52" + integrity sha512-3mA9N7wKM+nEFemBo1vCNgypJBFv2WvBXeacLx9b+Z8sueW1cUHq6p5fQ9aIBDK0DNBvtqhhW+79hdJPUHGwrA== htmlparser2@^6.1.0: version "6.1.0" @@ -4327,9 +4327,9 @@ loader-runner@^4.2.0: integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== loader-utils@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.3.tgz#d4b15b8504c63d1fc3f2ade52d41bc8459d6ede1" - integrity sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A== + version "2.0.4" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" + integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" @@ -4402,9 +4402,9 @@ marked@4.0.12: integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ== marked@^4.0.3: - version "4.2.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.2.tgz#1d2075ad6cdfe42e651ac221c32d949a26c0672a" - integrity sha512-JjBTFTAvuTgANXx82a5vzK9JLSMoV6V3LBVn4Uhdso6t7vXrGx7g1Cd2r6NYSsxrYbQGFCMqBDhFHyK5q2UvcQ== + version "4.2.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.3.tgz#bd76a5eb510ff1d8421bc6c3b2f0b93488c15bea" + integrity sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw== mdn-data@2.0.14: version "2.0.14" @@ -4417,9 +4417,9 @@ media-typer@0.3.0: integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memfs@^3.4.3: - version "3.4.10" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.10.tgz#4cdff7cfd21351a85e11b08aa276ebf100210a4d" - integrity sha512-0bCUP+L79P4am30yP1msPzApwuMQG23TjwlwdHeEV5MxioDR1a0AgB0T9FfggU52eJuDCq8WVwb5ekznFyWiTQ== + version "3.4.12" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.12.tgz#d00f8ad8dab132dc277c659dc85bfd14b07d03bd" + integrity sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw== dependencies: fs-monkey "^1.0.3" @@ -4481,9 +4481,9 @@ mimic-fn@^2.1.0: integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mini-css-extract-plugin@^2.6.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e" - integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg== + version "2.7.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz#d7d9ba0c5b596d155e36e2b174082fc7f010dd64" + integrity sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw== dependencies: schema-utils "^4.0.0" @@ -4526,9 +4526,9 @@ minipass-pipeline@^1.2.2: minipass "^3.0.0" minipass@^3.0.0, minipass@^3.1.1: - version "3.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae" - integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" @@ -5188,17 +5188,17 @@ postcss-reduce-transforms@^5.1.0: postcss-value-parser "^4.2.0" postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9: - version "6.0.10" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" - integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + version "6.0.11" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc" + integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" postcss-simple-vars@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-7.0.0.tgz#f1d10a979762aa4e7e3450a35a32885112893d1b" - integrity sha512-SPSkKQK7mKjD/tqcTbZkDi3KP+C/cTGXnKQmSt3AisJtnZE6ZxHEUoOGRfpV0B5dW1Y36EETfRHx10WLHpXThA== + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz#836b3097a54dcd13dbd3c36a5dbdd512fad2954c" + integrity sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A== postcss-svgo@^5.1.0: version "5.1.0" @@ -5220,10 +5220,10 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.2.14, postcss@^8.4.12, postcss@^8.4.17, postcss@^8.4.7: - version "8.4.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.18.tgz#6d50046ea7d3d66a85e0e782074e7203bc7fbca2" - integrity sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA== +postcss@^8.2.14, postcss@^8.4.12, postcss@^8.4.17, postcss@^8.4.18: + version "8.4.19" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" + integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== dependencies: nanoid "^3.3.4" picocolors "^1.0.0" @@ -5389,14 +5389,14 @@ regenerate@^1.4.2: integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== regenerator-runtime@^0.13.10, regenerator-runtime@^0.13.9: - version "0.13.10" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee" - integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw== + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== regenerator-transform@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" - integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== dependencies: "@babel/runtime" "^7.8.4" @@ -5415,16 +5415,16 @@ regexp.prototype.flags@^1.2.0: functions-have-names "^1.2.2" regexpu-core@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139" - integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ== + version "5.2.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.2.tgz#3e4e5d12103b64748711c3aad69934d7718e75fc" + integrity sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw== dependencies: regenerate "^1.4.2" regenerate-unicode-properties "^10.1.0" regjsgen "^0.7.1" regjsparser "^0.9.1" unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" regjsgen@^0.7.1: version "0.7.1" @@ -5630,7 +5630,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== @@ -6068,9 +6068,9 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.0: terser "^5.14.1" terser@^5.14.1, terser@^5.3.4: - version "5.15.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c" - integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw== + version "5.16.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.0.tgz#29362c6f5506e71545c73b069ccd199bb28f7f54" + integrity sha512-KjTV81QKStSfwbNiwlBXfcgMcOloyuRdb62/iLFPGBcVNF4EXjhdYBhYHmbJpiBrVxZhDvltE11j+LBQUxEEJg== dependencies: "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" @@ -6220,9 +6220,9 @@ typedarray@^0.0.6: integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typescript@^4.0.2: - version "4.8.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" - integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + version "4.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" + integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" @@ -6237,10 +6237,10 @@ unicode-match-property-ecmascript@^2.0.0: unicode-canonical-property-names-ecmascript "^2.0.0" unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== unicode-properties@^1.2.2: version "1.4.1"