Release 2.16 (#4780)

This commit is contained in:
Kevin Papst
2024-05-01 14:24:24 +02:00
committed by GitHub
parent 8f8d228fb3
commit 99c296a751
150 changed files with 2498 additions and 1905 deletions

View File

@@ -23,6 +23,7 @@ import {
Legend,
Title,
Tooltip,
Colors,
// SubTitle
} from 'chart.js';
@@ -50,6 +51,7 @@ Chart.register(
Legend,
Title,
Tooltip,
Colors
// SubTitle
);

View File

@@ -19,7 +19,6 @@ export default class KimaiAPI extends KimaiPlugin {
_headers() {
const headers = new Headers();
headers.append('X-AUTH-SESSION', '1');
headers.append('Content-Type', 'application/json');
return headers;

View File

@@ -198,9 +198,6 @@
"symfony/symfony": "*"
},
"extra": {
"branch-alias": {
"dev-main": "2.0.x-dev"
},
"symfony": {
"id": "01C3FWRDJJEX9K6Y3A4XDFXPBR",
"allow-contrib": true,

1096
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -386,8 +386,8 @@
],
'en_ID' =>
[
'date' => 'M/d/yy',
'time' => 'HH:mm',
'date' => 'dd/MM/y',
'time' => 'HH.mm',
'rtl' => false,
'translation' => false,
],
@@ -603,7 +603,7 @@
],
'en_NZ' =>
[
'date' => 'd/MM/yy',
'date' => 'dd/MM/y',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
@@ -870,14 +870,14 @@
'es_AR' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_BO' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -898,7 +898,7 @@
'es_CL' =>
[
'date' => 'dd-MM-yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -912,14 +912,14 @@
'es_CR' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_CU' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -933,7 +933,7 @@
'es_EC' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -954,28 +954,28 @@
'es_GT' =>
[
'date' => 'd/MM/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_HN' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_MX' =>
[
'date' => 'dd/MM/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_NI' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -989,7 +989,7 @@
'es_PE' =>
[
'date' => 'd/MM/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -1010,14 +1010,14 @@
'es_PY' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
'es_SV' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -1031,7 +1031,7 @@
'es_UY' =>
[
'date' => 'd/M/yy',
'time' => 'HH:mm',
'time' => 'h:mm a',
'rtl' => false,
'translation' => false,
],
@@ -1835,7 +1835,7 @@
],
'sl' =>
[
'date' => 'd. MM. yy',
'date' => 'd. M. yy',
'time' => 'HH:mm',
'rtl' => false,
'translation' => true,
@@ -1905,14 +1905,14 @@
],
'vi' =>
[
'date' => 'dd/MM/y',
'date' => 'd/M/yy',
'time' => 'HH:mm',
'rtl' => false,
'translation' => true,
],
'vi_VN' =>
[
'date' => 'dd/MM/y',
'date' => 'd/M/yy',
'time' => 'HH:mm',
'rtl' => false,
'translation' => false,
@@ -1931,4 +1931,11 @@
'rtl' => false,
'translation' => true,
],
'zh_Hant_TW' =>
[
'date' => 'y/M/d',
'time' => 'Bh:mm',
'rtl' => false,
'translation' => true,
],
];

View File

@@ -22,6 +22,7 @@ doctrine:
types:
datetime: App\Doctrine\UTCDateTimeType
datetime_immutable: App\Doctrine\UTCDateTimeImmutableType
orm:
controller_resolver:
auto_mapping: true

View File

@@ -0,0 +1,7 @@
framework:
rate_limiter:
session_prediction:
policy: 'fixed_window'
limit: 250
interval: '1 hour'
lock_factory: null

View File

@@ -63,7 +63,7 @@ security:
logout:
path: logout
target: homepage
enable_csrf: true
enable_csrf: false
login_throttling:
max_attempts: 5
@@ -76,6 +76,7 @@ security:
max_uses: 1
access_decision_manager:
# only grants access if there is no voter denying access
strategy: unanimous
allow_if_all_abstain: false

View File

@@ -122,7 +122,7 @@ tabler:
search: fas fa-search
settings: fas fa-cog
shop: fas fa-shopping-cart
spinner: fas fa-spinner fa-pulse
spinner: fas fa-spinner
start: fas fa-play
start-small: far fa-play-circle
stop: fas fa-stop

View File

@@ -1,7 +1,7 @@
parameters:
locale: en
# can be regenerated with "bin/console kimai:reset:locales"
app_locales: ar|cs|da|de|de_CH|el|en|eo|es|eu|fa|fi|fo|fr|he|hr|hu|id|it|ja|ko|nb_NO|nl|pa|pl|pt|pt_BR|ro|ru|sk|sl|sv|tr|uk|vi|zh_CN|zh_Hant|cs_CZ|da_DK|da_GL|de_AT|de_BE|de_CH|de_DE|de_IT|de_LI|de_LU|el_CY|el_GR|en_AE|en_AG|en_AI|en_AS|en_AT|en_AU|en_BB|en_BE|en_BI|en_BM|en_BS|en_BW|en_BZ|en_CA|en_CC|en_CH|en_CK|en_CM|en_CX|en_CY|en_DE|en_DG|en_DK|en_DM|en_ER|en_FI|en_FJ|en_FK|en_FM|en_GB|en_GD|en_GG|en_GH|en_GI|en_GM|en_GU|en_GY|en_HK|en_ID|en_IE|en_IL|en_IM|en_IN|en_IO|en_JE|en_JM|en_KE|en_KI|en_KN|en_KY|en_LC|en_LR|en_LS|en_MG|en_MH|en_MO|en_MP|en_MS|en_MT|en_MU|en_MV|en_MW|en_MY|en_NA|en_NF|en_NG|en_NH|en_NL|en_NR|en_NU|en_NZ|en_PG|en_PH|en_PK|en_PN|en_PR|en_PW|en_RH|en_RW|en_SB|en_SC|en_SD|en_SE|en_SG|en_SH|en_SI|en_SL|en_SS|en_SX|en_SZ|en_TC|en_TK|en_TO|en_TT|en_TV|en_TZ|en_UG|en_UM|en_US|en_VC|en_VG|en_VI|en_VU|en_WS|en_ZA|en_ZM|en_ZW|es_AR|es_BO|es_BR|es_BZ|es_CL|es_CO|es_CR|es_CU|es_DO|es_EA|es_EC|es_ES|es_GQ|es_GT|es_HN|es_IC|es_MX|es_NI|es_PA|es_PE|es_PH|es_PR|es_PY|es_SV|es_US|es_UY|es_VE|eu_ES|fa_AF|fa_IR|fi_FI|fo_DK|fo_FO|fr_BE|fr_BF|fr_BI|fr_BJ|fr_BL|fr_CA|fr_CD|fr_CF|fr_CG|fr_CH|fr_CI|fr_CM|fr_DJ|fr_DZ|fr_FR|fr_GA|fr_GF|fr_GN|fr_GP|fr_GQ|fr_HT|fr_KM|fr_LU|fr_MA|fr_MC|fr_MF|fr_MG|fr_ML|fr_MQ|fr_MR|fr_MU|fr_NC|fr_NE|fr_PF|fr_PM|fr_RE|fr_RW|fr_SC|fr_SN|fr_SY|fr_TD|fr_TG|fr_TN|fr_VU|fr_WF|fr_YT|he_IL|hr_BA|hr_HR|hu_HU|it_CH|it_IT|it_SM|it_VA|ja_JP|ko_CN|ko_KP|ko_KR|nl_AW|nl_BE|nl_BQ|nl_CW|nl_NL|nl_SR|nl_SX|pl_PL|pt_AO|pt_BR|pt_CH|pt_CV|pt_GQ|pt_GW|pt_LU|pt_MO|pt_MZ|pt_PT|pt_ST|pt_TL|ro_MD|ro_RO|ru_BY|ru_KG|ru_KZ|ru_MD|ru_RU|ru_UA|sk_SK|sv_AX|sv_FI|sv_SE|tr_CY|tr_TR|uk_UA|vi_VN
app_locales: ar|cs|da|de|de_CH|el|en|eo|es|eu|fa|fi|fo|fr|he|hr|hu|id|it|ja|ko|nb_NO|nl|pa|pl|pt|pt_BR|ro|ru|sk|sl|sv|tr|uk|vi|zh_CN|zh_Hant|zh_Hant_TW|cs_CZ|da_DK|da_GL|de_AT|de_BE|de_CH|de_DE|de_IT|de_LI|de_LU|el_CY|el_GR|en_AE|en_AG|en_AI|en_AS|en_AT|en_AU|en_BB|en_BE|en_BI|en_BM|en_BS|en_BW|en_BZ|en_CA|en_CC|en_CH|en_CK|en_CM|en_CX|en_CY|en_DE|en_DG|en_DK|en_DM|en_ER|en_FI|en_FJ|en_FK|en_FM|en_GB|en_GD|en_GG|en_GH|en_GI|en_GM|en_GU|en_GY|en_HK|en_ID|en_IE|en_IL|en_IM|en_IN|en_IO|en_JE|en_JM|en_KE|en_KI|en_KN|en_KY|en_LC|en_LR|en_LS|en_MG|en_MH|en_MO|en_MP|en_MS|en_MT|en_MU|en_MV|en_MW|en_MY|en_NA|en_NF|en_NG|en_NH|en_NL|en_NR|en_NU|en_NZ|en_PG|en_PH|en_PK|en_PN|en_PR|en_PW|en_RH|en_RW|en_SB|en_SC|en_SD|en_SE|en_SG|en_SH|en_SI|en_SL|en_SS|en_SX|en_SZ|en_TC|en_TK|en_TO|en_TT|en_TV|en_TZ|en_UG|en_UM|en_US|en_VC|en_VG|en_VI|en_VU|en_WS|en_ZA|en_ZM|en_ZW|es_AR|es_BO|es_BR|es_BZ|es_CL|es_CO|es_CR|es_CU|es_DO|es_EA|es_EC|es_ES|es_GQ|es_GT|es_HN|es_IC|es_MX|es_NI|es_PA|es_PE|es_PH|es_PR|es_PY|es_SV|es_US|es_UY|es_VE|eu_ES|fa_AF|fa_IR|fi_FI|fo_DK|fo_FO|fr_BE|fr_BF|fr_BI|fr_BJ|fr_BL|fr_CA|fr_CD|fr_CF|fr_CG|fr_CH|fr_CI|fr_CM|fr_DJ|fr_DZ|fr_FR|fr_GA|fr_GF|fr_GN|fr_GP|fr_GQ|fr_HT|fr_KM|fr_LU|fr_MA|fr_MC|fr_MF|fr_MG|fr_ML|fr_MQ|fr_MR|fr_MU|fr_NC|fr_NE|fr_PF|fr_PM|fr_RE|fr_RW|fr_SC|fr_SN|fr_SY|fr_TD|fr_TG|fr_TN|fr_VU|fr_WF|fr_YT|he_IL|hr_BA|hr_HR|hu_HU|it_CH|it_IT|it_SM|it_VA|ja_JP|ko_CN|ko_KP|ko_KR|nl_AW|nl_BE|nl_BQ|nl_CW|nl_NL|nl_SR|nl_SX|pl_PL|pt_AO|pt_BR|pt_CH|pt_CV|pt_GQ|pt_GW|pt_LU|pt_MO|pt_MZ|pt_PT|pt_ST|pt_TL|ro_MD|ro_RO|ru_BY|ru_KG|ru_KZ|ru_MD|ru_RU|ru_UA|sk_SK|sv_AX|sv_FI|sv_SE|tr_CY|tr_TR|uk_UA|vi_VN
services:
# default configuration for services in *this* file

View File

@@ -24,10 +24,10 @@
],
"packageManager": "yarn@3.2.1",
"devDependencies": {
"@babel/core": "^7.19.6",
"@babel/eslint-parser": "^7.18.2",
"@babel/preset-env": "^7.19.4",
"@fortawesome/fontawesome-free": "^6.5.0",
"@babel/core": "^7.19",
"@babel/eslint-parser": "^7.19",
"@babel/preset-env": "^7.19",
"@fortawesome/fontawesome-free": "^6.5",
"@fullcalendar/bootstrap5": "^5.11",
"@fullcalendar/core": "^5.11",
"@fullcalendar/daygrid": "^5.11",
@@ -37,17 +37,17 @@
"@fullcalendar/timegrid": "^5.11",
"@symfony/webpack-encore": "^4.0",
"@tabler/core": "1.0.0-beta19",
"chart.js": "^3.9",
"chart.js": "^4.0",
"core-js": "^3.6",
"eslint": "^8.0",
"eslint-webpack-plugin": "^3.0",
"gridstack": "^7.1",
"litepicker": "^2.0",
"luxon": "^3.3",
"sass": "^1.62.1",
"sass": "^1.62",
"sass-loader": "^13.2",
"tom-select": "^2.2",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
"webpack": "^5.91",
"webpack-cli": "^4.10"
}
}

View File

@@ -1253,11 +1253,6 @@ parameters:
count: 1
path: src/Doctrine/TimesheetSubscriber.php
-
message: "#^Parameter \\#2 \\$datetime of static method DateTime\\:\\:createFromFormat\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Doctrine/UTCDateTimeType.php
-
message: "#^Method App\\\\Entity\\\\Activity\\:\\:__toString\\(\\) should return string but returns string\\|null\\.$#"
count: 1
@@ -3280,7 +3275,7 @@ parameters:
-
message: "#^Parameter \\#1 \\$inputTimezone of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToLocalizedStringTransformer constructor expects string\\|null, mixed given\\.$#"
count: 1
count: 2
path: src/Form/Type/DateRangeType.php
-
@@ -3290,7 +3285,7 @@ parameters:
-
message: "#^Parameter \\#2 \\$outputTimezone of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToLocalizedStringTransformer constructor expects string\\|null, mixed given\\.$#"
count: 1
count: 2
path: src/Form/Type/DateRangeType.php
-
@@ -3778,11 +3773,6 @@ parameters:
count: 2
path: src/Kernel.php
-
message: "#^Method App\\\\Kernel\\:\\:configureContainer\\(\\) has no return type specified\\.$#"
count: 1
path: src/Kernel.php
-
message: "#^Method App\\\\Kernel\\:\\:getBundleClasses\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[535],{1548:function(i,n,u){u(846)},846:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=1548,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[113],{2395:function(i,n,u){u(3865)},3865:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=2395,i(i.s=n)}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,13 +1,13 @@
/*!
* @kurkle/color v0.2.1
* @kurkle/color v0.3.2
* https://github.com/kurkle/color#readme
* (c) 2022 Jukka Kurkela
* (c) 2023 Jukka Kurkela
* Released under the MIT License
*/
/*!
* Chart.js v3.9.1
* Chart.js v4.4.2
* https://www.chartjs.org
* (c) 2022 Chart.js Contributors
* (c) 2024 Chart.js Contributors
* Released under the MIT License
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,26 +2,26 @@
"entrypoints": {
"app": {
"js": [
"/build/runtime.f0079159.js",
"/build/app.6450be5e.js"
"/build/runtime.74179306.js",
"/build/app.cde83469.js"
],
"css": [
"/build/app.3501ccee.css"
"/build/app.ee4f7e19.css"
]
},
"app-rtl": {
"js": [
"/build/runtime.f0079159.js",
"/build/app-rtl.3d445498.js"
"/build/runtime.74179306.js",
"/build/app-rtl.97153087.js"
],
"css": [
"/build/app-rtl.670658da.css"
"/build/app-rtl.db588f2b.css"
]
},
"export-pdf": {
"js": [
"/build/runtime.f0079159.js",
"/build/export-pdf.d367a32e.js"
"/build/runtime.74179306.js",
"/build/export-pdf.1442bee7.js"
],
"css": [
"/build/export-pdf.d8a6c23b.css"
@@ -29,8 +29,8 @@
},
"invoice": {
"js": [
"/build/runtime.f0079159.js",
"/build/invoice.2604495e.js"
"/build/runtime.74179306.js",
"/build/invoice.7ef8a0c8.js"
],
"css": [
"/build/invoice.5bea118e.css"
@@ -38,8 +38,8 @@
},
"invoice-pdf": {
"js": [
"/build/runtime.f0079159.js",
"/build/invoice-pdf.ce9aace0.js"
"/build/runtime.74179306.js",
"/build/invoice-pdf.6091a528.js"
],
"css": [
"/build/invoice-pdf.2b749265.css"
@@ -47,14 +47,14 @@
},
"chart": {
"js": [
"/build/runtime.f0079159.js",
"/build/chart.f5becfac.js"
"/build/runtime.74179306.js",
"/build/chart.80ee190c.js"
]
},
"calendar": {
"js": [
"/build/runtime.f0079159.js",
"/build/calendar.d45e4af5.js"
"/build/runtime.74179306.js",
"/build/calendar.bb629e51.js"
],
"css": [
"/build/calendar.bb473428.css"
@@ -62,8 +62,8 @@
},
"dashboard": {
"js": [
"/build/runtime.f0079159.js",
"/build/dashboard.6774a712.js"
"/build/runtime.74179306.js",
"/build/dashboard.10118fb0.js"
],
"css": [
"/build/dashboard.18f5a8b7.css"
@@ -71,21 +71,21 @@
}
},
"integrity": {
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
"/build/app.6450be5e.js": "sha384-P5Qc8Rav736nZcS2vqM2rBRZpr3bwMsk4SJENBsOMDPdfEjDX7M8WMpwhjzxj0PQ",
"/build/app.3501ccee.css": "sha384-3chwmsldxvcA6ldtsAftB9R2/bSNCi17vSW9ycC0FqLNNM+IdnMorRBXh/zTW1NF",
"/build/app-rtl.3d445498.js": "sha384-D5VYIVdHCPGzAPnMAIkRN1Ri9H4DxdwGts1BgG40JXJuOamq6UQXblaDBSpszOZ0",
"/build/app-rtl.670658da.css": "sha384-Mo5HQ+W9EWDGM1gOyEZ7aScXNltzBMQa4cWC1HtShvs4XPMNUwzOb97jcXf34qSD",
"/build/export-pdf.d367a32e.js": "sha384-Z5baqnzjI636nYFs4g63ViIKBZKRW4Jhv/7PQmTEQlqhfA7eK0vUMUtiyy0R5A9u",
"/build/runtime.74179306.js": "sha384-OC1hTNUXUalKJcvmzrZ0TMCOIwnhxCxgG9dQkbcwR7WcBBCkl2H8bs3giiT2pAwG",
"/build/app.cde83469.js": "sha384-829jYMX4FgmjcB0IV2HWYYOEviCyDD55lOX4fXXWUmUgDuDXXFZMyPFEEcK93dWR",
"/build/app.ee4f7e19.css": "sha384-7E3ujVsOCkGatHu6khaWWqYhPkc85k22zuXZOwOVo1MlWcPSEBhS65Y0qbeWXdAp",
"/build/app-rtl.97153087.js": "sha384-jX7jRUAa8rH29Eg8jLIUKGfGcOT6RBz/P90plXmZPadf2CXKUBdcNGrspaejCHkr",
"/build/app-rtl.db588f2b.css": "sha384-OwYS82WpkkoVqI38n3gGpvMTiTFT+dUscgVglMw2vcDvIxAe2B3IcXMjHoCGm/gl",
"/build/export-pdf.1442bee7.js": "sha384-C6agvjJnQUsMCxaZ/J7dUZU3cpC7uHKI9ZtnfGpRqYbjyw91YLy1oV3iNYgwYyCF",
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
"/build/invoice.2604495e.js": "sha384-D6JvhGSqlx7z72b/qD3nF3QDXPy+XsCSRGtWfs1icjDKOcd2UzuXwuSa/E1Fg2TJ",
"/build/invoice.7ef8a0c8.js": "sha384-z4lZ1Ig3+NPigrRyGPZoff0gG3n5PnCjaDJ73ATnzdUYk0lOCEtNV9fg35VRD0vG",
"/build/invoice.5bea118e.css": "sha384-KNyGdZSTXnAi8Tn2WqrxJnCP18yRK7BrZTHKCAGAEtl5/4S/XAe4IHKpM5gfsmB7",
"/build/invoice-pdf.ce9aace0.js": "sha384-mtZkXrpsXFMX2YvmmTlCm91QgsTlZLzLJnDAFcTuBDtDZ7TNkqLYkfCeLzFLVfwb",
"/build/invoice-pdf.6091a528.js": "sha384-yJz/MDBgBpNHNxF7DuSyFbJN9EL7oDJjraoPRB7VYlHMdb1T0ZfTcI0L8VMDB46U",
"/build/invoice-pdf.2b749265.css": "sha384-DXXgkz2WWnrWnfBnXX5fmfPQSPb98upMnWxYKwTGYS04EhrPIWfDCutB2unIrWh7",
"/build/chart.f5becfac.js": "sha384-GSqETm8wULiVXyizvwRompfwu63r/C0Qd/AvrHDE4cqAKiIGCssb3QyBtGu1WN+W",
"/build/calendar.d45e4af5.js": "sha384-wi3/ek3Msn+rk9jebeJnzEXaHUUWlzxkOZwhZyJP5Cg+AKWtolWAXD/hCXQAg0kq",
"/build/chart.80ee190c.js": "sha384-KrQszq859PR0u+KHpGy+RO6K1rcMqCFZx+sNiLVNVZHwEi7RwTXqnYbu8zvfWzUI",
"/build/calendar.bb629e51.js": "sha384-uihkC7VSrD8l4gSiveJxM2g8dLFCR9+VQwVmcIb2LlNmA2PKDQ/uV0TN5gzmgpo+",
"/build/calendar.bb473428.css": "sha384-900W9o8666Qpw21rLP7hn5Ql8tWd40k0IcE3QpFm7E7V6bKva7xQgGlyzVuuh4GK",
"/build/dashboard.6774a712.js": "sha384-lBwkNqUPv+IBbznagiFakY2BOIueq/Bg89wHO2XeM9YAZ51rPkrvdMd+XmFupHsM",
"/build/dashboard.10118fb0.js": "sha384-pasZR1GYf8/7lMFS9OrsxX8nJ9tSlRYr32fWKUhGoF2mNAGrokLEWdgtbYMRHgFB",
"/build/dashboard.18f5a8b7.css": "sha384-PBD8ftb2yBoSjRe2sN5Xb4dEz045kOEUfcIufdSis+tWoWdAx5j4Yic+F/6CYbrP"
}
}

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[872],{878:function(i,n,u){u(6154)},6154:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=878,i(i.s=n)}]);

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[185],{8810:function(i,n,u){u(9508)},9508:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=8810,i(i.s=n)}]);

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[117],{1555:function(i,n,u){u(8837)},8837:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=1555,i(i.s=n)}]);

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[266],{35:function(i,n,u){u(6197)},6197:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=35,i(i.s=n)}]);

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[149],{474:function(i,n,u){u(9822)},9822:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=474,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[896],{4820:function(i,n,u){u(5650)},5650:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=4820,i(i.s=n)}]);

View File

@@ -1,24 +1,24 @@
{
"build/app.css": "/build/app.3501ccee.css",
"build/app.js": "/build/app.6450be5e.js",
"build/app-rtl.css": "/build/app-rtl.670658da.css",
"build/app-rtl.js": "/build/app-rtl.3d445498.js",
"build/app.css": "/build/app.ee4f7e19.css",
"build/app.js": "/build/app.cde83469.js",
"build/app-rtl.css": "/build/app-rtl.db588f2b.css",
"build/app-rtl.js": "/build/app-rtl.97153087.js",
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
"build/export-pdf.js": "/build/export-pdf.d367a32e.js",
"build/export-pdf.js": "/build/export-pdf.1442bee7.js",
"build/invoice.css": "/build/invoice.5bea118e.css",
"build/invoice.js": "/build/invoice.2604495e.js",
"build/invoice.js": "/build/invoice.7ef8a0c8.js",
"build/invoice-pdf.css": "/build/invoice-pdf.2b749265.css",
"build/invoice-pdf.js": "/build/invoice-pdf.ce9aace0.js",
"build/chart.js": "/build/chart.f5becfac.js",
"build/invoice-pdf.js": "/build/invoice-pdf.6091a528.js",
"build/chart.js": "/build/chart.80ee190c.js",
"build/calendar.css": "/build/calendar.bb473428.css",
"build/calendar.js": "/build/calendar.d45e4af5.js",
"build/calendar.js": "/build/calendar.bb629e51.js",
"build/dashboard.css": "/build/dashboard.18f5a8b7.css",
"build/dashboard.js": "/build/dashboard.6774a712.js",
"build/runtime.js": "/build/runtime.f0079159.js",
"build/fonts/fa-solid-900.ttf": "/build/fonts/fa-solid-900.bb5be820.ttf",
"build/fonts/fa-brands-400.ttf": "/build/fonts/fa-brands-400.4c05cd9b.ttf",
"build/fonts/fa-solid-900.woff2": "/build/fonts/fa-solid-900.4cbe3db2.woff2",
"build/fonts/fa-brands-400.woff2": "/build/fonts/fa-brands-400.498f4d22.woff2",
"build/fonts/fa-regular-400.ttf": "/build/fonts/fa-regular-400.96e19e1a.ttf",
"build/fonts/fa-regular-400.woff2": "/build/fonts/fa-regular-400.83824cd5.woff2"
"build/dashboard.js": "/build/dashboard.10118fb0.js",
"build/runtime.js": "/build/runtime.74179306.js",
"build/fonts/fa-solid-900.ttf": "/build/fonts/fa-solid-900.bacd5de6.ttf",
"build/fonts/fa-brands-400.ttf": "/build/fonts/fa-brands-400.60127e35.ttf",
"build/fonts/fa-solid-900.woff2": "/build/fonts/fa-solid-900.4d986b00.woff2",
"build/fonts/fa-brands-400.woff2": "/build/fonts/fa-brands-400.455ea818.woff2",
"build/fonts/fa-regular-400.ttf": "/build/fonts/fa-regular-400.eb91f7b9.ttf",
"build/fonts/fa-regular-400.woff2": "/build/fonts/fa-regular-400.21cb8f55.woff2"
}

View File

@@ -1 +1 @@
!function(){"use strict";var e,r={},n={};function t(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,loaded:!1,exports:{}};return r[e].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}t.m=r,t.amdO={},e=[],t.O=function(r,n,o,i){if(!n){var u=1/0;for(l=0;l<e.length;l++){n=e[l][0],o=e[l][1],i=e[l][2];for(var f=!0,a=0;a<n.length;a++)(!1&i||u>=i)&&Object.keys(t.O).every((function(e){return t.O[e](n[a])}))?n.splice(a--,1):(f=!1,i<u&&(u=i));if(f){e.splice(l--,1);var c=o();void 0!==c&&(r=c)}}return r}i=i||0;for(var l=e.length;l>0&&e[l-1][2]>i;l--)e[l]=e[l-1];e[l]=[n,o,i]},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,{a:r}),r},t.d=function(e,r){for(var n in r)t.o(r,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e={666:0};t.O.j=function(r){return 0===e[r]};var r=function(r,n){var o,i,u=n[0],f=n[1],a=n[2],c=0;if(u.some((function(r){return 0!==e[r]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(a)var l=a(t)}for(r&&r(n);c<u.length;c++)i=u[c],t.o(e,i)&&e[i]&&e[i][0](),e[i]=0;return t.O(l)},n=self.webpackChunkkimai2=self.webpackChunkkimai2||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))}()}();
!function(){"use strict";var e,r={},n={};function t(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,loaded:!1,exports:{}};return r[e].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}t.m=r,t.amdO={},e=[],t.O=function(r,n,o,i){if(!n){var u=1/0;for(l=0;l<e.length;l++){n=e[l][0],o=e[l][1],i=e[l][2];for(var f=!0,a=0;a<n.length;a++)(!1&i||u>=i)&&Object.keys(t.O).every((function(e){return t.O[e](n[a])}))?n.splice(a--,1):(f=!1,i<u&&(u=i));if(f){e.splice(l--,1);var c=o();void 0!==c&&(r=c)}}return r}i=i||0;for(var l=e.length;l>0&&e[l-1][2]>i;l--)e[l]=e[l-1];e[l]=[n,o,i]},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,{a:r}),r},t.d=function(e,r){for(var n in r)t.o(r,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e={121:0};t.O.j=function(r){return 0===e[r]};var r=function(r,n){var o,i,u=n[0],f=n[1],a=n[2],c=0;if(u.some((function(r){return 0!==e[r]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(a)var l=a(t)}for(r&&r(n);c<u.length;c++)i=u[c],t.o(e,i)&&e[i]&&e[i][0](),e[i]=0;return t.O(l)},n=self.webpackChunkkimai2=self.webpackChunkkimai2||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))}()}();

View File

@@ -27,7 +27,8 @@ final class ApiRequestMatcher implements RequestMatcherInterface
}
// let's use this firewall if a Bearer token is set in the header
if ($request->headers->has('Authorization')) {
// other cases like "bearer" are rejected earlier
if (($auth = $request->headers->get('Authorization')) !== null && str_starts_with($auth, 'Bearer ')) {
return true;
}

View File

@@ -232,7 +232,7 @@ final class UserController extends BaseApiController
throw $this->createAccessDeniedException('User has no access to API tokens');
}
if ($accessToken->getUser() !== $user) {
if (!$this->isGranted('api-token', $accessToken->getUser())) {
throw $this->createAccessDeniedException('You are not allowed to delete this access token');
}

View File

@@ -40,6 +40,12 @@ final class RegenerateLocalesCommand extends Command
* @var string[]
*/
private array $noRegionCode = ['ar', 'id', 'pa', 'sl'];
/**
* A list of locales that will be activated, not matter if translation files exist for them.
*
* @var string[]
*/
private array $addLocaleToList = ['zh_Hant_TW'];
public function __construct(
private readonly string $projectDirectory,
@@ -74,8 +80,8 @@ final class RegenerateLocalesCommand extends Command
foreach ($translationFilenames as $file) {
$firstLevelLocales[] = explode('.', basename($file))[1];
}
$firstLevelLocales = array_unique($firstLevelLocales);
$io->title('Locales found from translation files');
$firstLevelLocales = array_unique(array_merge($firstLevelLocales, $this->addLocaleToList));
$io->title('First level locales found');
$io->writeln(implode('|', $firstLevelLocales));
$secondLevel = [];
@@ -95,7 +101,7 @@ final class RegenerateLocalesCommand extends Command
sort($firstLevelLocales);
sort($secondLevel);
// keep the locales that have translation filesat the begin
// keep the locales that have translation files at the beginning
// the config is than easier to read and the locales will be sorted in the UI anyway
$locales = array_merge($firstLevelLocales, $secondLevel);

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.15.0';
public const VERSION = '2.16.0';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 21500;
public const VERSION_ID = 21600;
/**
* The software name
*/

View File

@@ -12,7 +12,7 @@ namespace App\Controller;
use App\Constants;
use App\Utils\PageSetup;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
#[Route(path: '/about')]
final class AboutController extends AbstractController

View File

@@ -42,7 +42,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -14,7 +14,7 @@ use App\Saml\SamlAuthFactory;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\SecurityRequestAttributes;

View File

@@ -14,7 +14,7 @@ use App\Repository\BookmarkRepository;
use App\Utils\ProfileManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\RuntimeException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

View File

@@ -17,7 +17,7 @@ use App\Timesheet\TrackingModeService;
use App\Utils\PageSetup;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -19,7 +19,7 @@ use App\WorkingTime\WorkingTimeService;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
/**
* Users can control their working time statistics

View File

@@ -43,7 +43,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;

View File

@@ -21,7 +21,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -15,7 +15,7 @@ use App\Utils\PageSetup;
use App\Utils\ReleaseVersion;
use Composer\InstalledVersions;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;

View File

@@ -19,7 +19,7 @@ use App\Utils\PageSetup;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -12,7 +12,7 @@ namespace App\Controller;
use App\Entity\Timesheet;
use App\Timesheet\FavoriteRecordService;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/favorite')]

View File

@@ -19,7 +19,7 @@ use Pagerfanta\Adapter\ArrayAdapter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Intl\Locales;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/help')]

View File

@@ -16,7 +16,7 @@ use App\Repository\UserRepository;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -45,7 +45,7 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;

View File

@@ -27,7 +27,7 @@ use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;

View File

@@ -12,7 +12,7 @@ namespace App\Controller;
use App\Plugin\PluginManager;
use App\Utils\PageSetup;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;

View File

@@ -43,7 +43,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
@@ -173,7 +173,7 @@ final class ProfileController extends AbstractController
$this->flashSuccess('action.update.success');
$request->getSession()->set('_show_access_token', $accessToken->getId());
return new Response();
return $this->redirectToRoute('user_profile_api_token', ['username' => $profile->getUserIdentifier()]);
}
return $this->render('user/access-token.html.twig', [

View File

@@ -47,7 +47,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;

View File

@@ -19,7 +19,7 @@ use App\Timesheet\TimesheetService;
use App\Utils\PageSetup;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -21,7 +21,7 @@ use App\Repository\UserRepository;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/reporting/customer/monthly_projects')]

View File

@@ -18,7 +18,7 @@ use App\Reporting\ProjectDateRange\ProjectDateRangeQuery;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
final class ProjectDateRangeController extends AbstractController

View File

@@ -17,7 +17,7 @@ use App\Utils\PageSetup;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
final class ProjectDetailsController extends AbstractController

View File

@@ -16,7 +16,7 @@ use App\Reporting\ProjectInactive\ProjectInactiveQuery;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
final class ProjectInactiveController extends AbstractController

View File

@@ -16,7 +16,7 @@ use App\Reporting\ProjectView\ProjectViewQuery;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
final class ProjectViewController extends AbstractController

View File

@@ -23,7 +23,7 @@ use App\Timesheet\TimesheetStatisticService;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/reporting/users')]

View File

@@ -23,7 +23,7 @@ use App\Timesheet\TimesheetStatisticService;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/reporting/users')]

View File

@@ -24,7 +24,7 @@ use App\Timesheet\TimesheetStatisticService;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/reporting/users')]

View File

@@ -19,7 +19,7 @@ use Exception;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Attribute\IsGranted;
@@ -113,6 +113,8 @@ final class UserMonthController extends AbstractUserReportController
'current' => $start,
'next' => $nextMonth,
'previous' => $previousMonth,
'begin' => $start,
'end' => $end,
'export_route' => 'report_user_month_export',
];
}

View File

@@ -18,7 +18,7 @@ use Exception;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Attribute\IsGranted;
@@ -106,6 +106,8 @@ final class UserWeekController extends AbstractUserReportController
'current' => $start,
'next' => $next,
'previous' => $previous,
'begin' => $start,
'end' => $end,
'export_route' => 'report_user_week_export',
];
}

View File

@@ -23,7 +23,7 @@ use Exception;
use PhpOffice\PhpSpreadsheet\Reader\Html;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Attribute\IsGranted;
@@ -122,6 +122,8 @@ final class UserYearController extends AbstractUserReportController
'current' => $start,
'next' => $next,
'previous' => $previous,
'begin' => $start,
'end' => $end,
'export_route' => 'report_user_year_export',
];
}

View File

@@ -12,7 +12,7 @@ namespace App\Controller;
use App\Reporting\ReportingService;
use App\Utils\PageSetup;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -11,7 +11,7 @@ namespace App\Controller\Security;
use App\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
#[Route(path: '/auth/link')]
/**

View File

@@ -24,7 +24,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

View File

@@ -12,7 +12,7 @@ namespace App\Controller\Security;
use App\Configuration\SamlConfigurationInterface;
use App\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

View File

@@ -25,7 +25,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

View File

@@ -45,7 +45,7 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Component\Validator\Constraints\NotBlank;

View File

@@ -21,7 +21,7 @@ use App\Utils\PageSetup;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/admin/tags')]

View File

@@ -22,7 +22,7 @@ use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/admin/teams')]

View File

@@ -16,7 +16,7 @@ use App\Form\TimesheetEditForm;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -24,7 +24,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -30,7 +30,7 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**

View File

@@ -10,7 +10,7 @@
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/widgets')]

View File

@@ -20,7 +20,7 @@ use App\User\UserService;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route(path: '/wizard')]
@@ -28,7 +28,6 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
final class WizardController extends AbstractController
{
#[Route(path: '/{wizard}', name: 'wizard', methods: ['GET', 'POST'])]
#[IsGranted('view_own_timesheet')]
public function wizard(Request $request, UserService $userService, string $wizard): Response
{
$user = $this->getUser();

View File

@@ -0,0 +1,77 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Doctrine;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeImmutableType;
use Doctrine\DBAL\Types\Types;
final class UTCDateTimeImmutableType extends DateTimeImmutableType
{
/**
* @var \DateTimeZone|null
*/
private static ?\DateTimeZone $utc = null;
/**
* @param T $value
* @return (T is null ? null : string)
* @template T<\DateTimeImmutable>
* @throws ConversionException
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value instanceof \DateTimeImmutable) {
$value = clone $value;
$value = $value->setTimezone(self::getUtc());
}
return parent::convertToDatabaseValue($value, $platform);
}
public static function getUtc(): \DateTimeZone
{
if (self::$utc === null) {
self::$utc = new \DateTimeZone('UTC');
}
return self::$utc;
}
/**
* @param mixed $value
* @throws ConversionException
*/
public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeImmutable
{
if (null === $value || $value instanceof \DateTimeImmutable) {
return $value;
}
if (\is_string($value)) {
$converted = \DateTimeImmutable::createFromFormat(
$platform->getDateTimeFormatString(),
$value,
self::getUtc()
);
if ($converted !== false) {
return $converted;
}
}
throw ConversionException::conversionFailedFormat(
$value,
Types::DATETIME_IMMUTABLE,
$platform->getDateTimeFormatString()
);
}
}

View File

@@ -49,8 +49,6 @@ final class UTCDateTimeType extends DateTimeType
/**
* @param mixed $value
* @param AbstractPlatform $platform
* @return null|\DateTime
* @throws ConversionException
*/
public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTime
@@ -59,20 +57,22 @@ final class UTCDateTimeType extends DateTimeType
return $value;
}
$converted = \DateTime::createFromFormat(
$platform->getDateTimeFormatString(),
$value,
self::getUtc()
);
if (!$converted) {
throw ConversionException::conversionFailedFormat(
if (\is_string($value)) {
$converted = \DateTime::createFromFormat(
$platform->getDateTimeFormatString(),
$value,
Types::DATETIME_MUTABLE,
$platform->getDateTimeFormatString()
self::getUtc()
);
if ($converted !== false) {
return $converted;
}
}
return $converted;
throw ConversionException::conversionFailedFormat(
$value,
Types::DATETIME_MUTABLE,
$platform->getDateTimeFormatString()
);
}
}

View File

@@ -190,7 +190,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
#[Assert\NotNull]
private ?string $category = self::WORK;
#[ORM\Column(name: 'modified_at', type: 'datetime_immutable', nullable: true)]
private \DateTimeImmutable $modifiedAt; // @phpstan-ignore-line - create migration and update all null values and then make it not null
private \DateTimeImmutable $modifiedAt;
/**
* Tags
*

View File

@@ -16,15 +16,11 @@ interface MetaDisplayEventInterface
{
/**
* If you want to filter where your meta-field will be displayed, use the query settings.
*
* @return BaseQuery
*/
public function getQuery(): BaseQuery;
/**
* If you want to filter where your meta-field will be displayed, check the current location.
*
* @return string
*/
public function getLocation(): string;
@@ -35,9 +31,6 @@ interface MetaDisplayEventInterface
/**
* Adds a field that should be displayed.
*
* @param MetaTableTypeInterface $meta
* @return void
*/
public function addField(MetaTableTypeInterface $meta) /* : void */;
public function addField(MetaTableTypeInterface $meta): void;
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\EventSubscriber;
use App\Security\SessionHandler;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Http\Event\LogoutEvent;
final class LogoutSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly SessionHandler $sessionHandler,
private readonly LoggerInterface $logger
)
{
}
public static function getSubscribedEvents(): array
{
return [
LogoutEvent::class => 'onLogout',
];
}
public function onLogout(LogoutEvent $event): void
{
try {
$this->sessionHandler->garbageCollection();
} catch (\Exception $exception) {
$this->logger->error('Failed removing expired session: ' . $exception->getMessage());
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export\Spreadsheet\CellFormatter;
use App\Utils\StringHelper;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
final class StringFormatter implements CellFormatterInterface
{
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
if (!\is_string($value)) {
throw new \InvalidArgumentException('Unsupported value given, only string is supported');
}
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), StringHelper::sanitizeDDE($value));
}
}

View File

@@ -15,6 +15,7 @@ use App\Export\Spreadsheet\CellFormatter\CellFormatterInterface;
use App\Export\Spreadsheet\CellFormatter\DateFormatter;
use App\Export\Spreadsheet\CellFormatter\DateTimeFormatter;
use App\Export\Spreadsheet\CellFormatter\DurationFormatter;
use App\Export\Spreadsheet\CellFormatter\StringFormatter;
use App\Export\Spreadsheet\CellFormatter\TimeFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@@ -30,7 +31,7 @@ class SpreadsheetExporter
*/
private array $formatter = [];
public function __construct(private TranslatorInterface $translator)
public function __construct(private readonly TranslatorInterface $translator)
{
$this->registerCellFormatter('datetime', new DateTimeFormatter());
$this->registerCellFormatter('date', new DateFormatter());
@@ -38,6 +39,7 @@ class SpreadsheetExporter
$this->registerCellFormatter('duration', new DurationFormatter());
$this->registerCellFormatter('boolean', new BooleanFormatter());
$this->registerCellFormatter('array', new ArrayFormatter());
$this->registerCellFormatter('string', new StringFormatter());
}
public function registerCellFormatter(string $type, CellFormatterInterface $formatter): void

Some files were not shown because too many files have changed in this diff Show More