Compare commits

...

243 Commits

Author SHA1 Message Date
Kevin Papst
2d5cef1a2f phpstan 2024-10-12 00:00:46 +02:00
Kevin Papst
52a9ff9860 Merge branch 'refs/heads/main' into activity-report
# Conflicts:
#	config/packages/kimai.yaml
#	phpstan.neon
#	src/Activity/ActivityStatisticService.php
#	src/Repository/ActivityRepository.php
2024-10-11 23:45:40 +02:00
Kevin Papst
ff9bf163ee Release 2.24 (#5097) 2024-10-11 21:56:54 +02:00
Kevin Papst
5fac6a642c Docker improvements (#5096)
* install missing unzip
* run update and install in one step
* remove unused TRUSTED_HOSTS env
2024-10-11 19:36:40 +02:00
Kevin Papst
b1b81ee8a6 remove dev dependencies from prod image 2024-10-04 17:35:25 +02:00
Kevin Papst
1ea64bf18e allow to manually run workflow 2024-10-04 17:03:31 +02:00
Kevin Papst
0c4fdda00a allow to manually run workflow 2024-10-04 17:01:25 +02:00
Kevin Papst
215bd6a01a allow to manually run workflow 2024-10-04 16:57:48 +02:00
Kevin Papst
63b8164926 install missing buildx 2024-10-04 16:45:51 +02:00
Weblate (bot)
8c26ff9aed Translated using Weblate (#5092)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
2024-10-04 11:24:50 +02:00
Kevin Papst
921a703ea2 Merge Docker images (#5094) 2024-10-04 11:14:10 +02:00
Kevin Papst
855a546683 Docker improvements (#5093) 2024-10-04 10:25:46 +02:00
Kevin Papst
52b949daa3 cleanup docker environment variables (#5074) 2024-10-03 14:27:33 +02:00
Weblate (bot)
ee040d29b6 Translations update from Hosted Weblate (#5079)
Co-authored-by: Doctorredits_here <alkaf.alkaf2018@tutamail.com>
Co-authored-by: Hien <hienly@yandex.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Ricky Tigg <ricky.tigg@gmail.com>
Co-authored-by: Roman Ondráček <mail@romanondracek.cz>
Co-authored-by: Tito Tapiola <ikirouta013@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Kevin Papst <kevinpapst@users.noreply.github.com>
2024-10-03 10:38:48 +02:00
Kevin Papst
fb9a0dc499 Release 2.23.0 (#5075) 2024-10-03 10:34:20 +02:00
Kevin Papst
40154be8f9 Upgrade Tabler frontend to 1.0.21 (#5066) 2024-09-23 18:31:33 +02:00
Kevin Papst
13649e146c Improve pagination support in API (#5073) 2024-09-22 17:26:02 +02:00
Kevin Papst
4076e1c3d3 Support for changeable work contract types (#5069) 2024-09-22 16:18:21 +02:00
Kevin Papst
8de54e1fa7 Added API endpoints to fetch invoices (#5070)
* added serializer attributes for API usage
* new setters to fill invoice data from fixture
* re-usable fixture helper methods
* added API endpoints to fetch invoices
* adjust tests
2024-09-22 16:17:45 +02:00
Weblate (bot)
1965c35b43 Translated using Weblate (#5045)
Co-authored-by: Doctorredits_here <alkaf.alkaf2018@tutamail.com>
Co-authored-by: Hien <hienly@yandex.com>
Co-authored-by: Jose Delvani <jsdelvani@users.noreply.hosted.weblate.org>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: albanobattistella <albano_battistella@hotmail.com>
Co-authored-by: enly sure <enlysure@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2024-09-22 15:38:51 +02:00
Kevin Papst
3fd770047e allow Authorization header in CORS request 2024-09-20 23:26:29 +02:00
Kevin Papst
036b297a76 fix hydration issues in favorites (#5068) 2024-09-20 22:43:16 +02:00
Kevin Papst
537c120ad9 Release 2.22.0 (#5043) 2024-09-20 14:30:11 +02:00
Weblate (bot)
3e0dadc0c8 Translated using Weblate (#5037)
Co-authored-by: Jose Delvani <jsdelvani@users.noreply.hosted.weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: hugoalh <hugoalh@users.noreply.hosted.weblate.org>
2024-09-01 14:58:47 +02:00
Kevin Papst
004ac5a6b9 re-phrase 2024-09-01 14:57:07 +02:00
Kevin Papst
3204dcb03e bump PHPSpreadsheet major version (#5040) 2024-08-31 23:42:41 +02:00
Kevin Papst
b1903ba183 Release 2.21.0 (#5014) 2024-08-28 17:16:37 +02:00
Weblate (bot)
75fa7a20b8 Translated using Weblate (#5012)
Co-authored-by: BeckeBauer <berko@gmx.de>
Co-authored-by: Biscuittttt <biscuitwithtea.tall310@passinbox.com>
Co-authored-by: Héctor Borrás Aleixandre <hborrasaleixandre@gmail.com>
Co-authored-by: John Titor <utkin2007@gmail.com>
Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Co-authored-by: Prefill add-on <noreply-addon-prefill@weblate.org>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Uporabnik Alen <obutimacek556@gmail.com>
Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Co-authored-by: tygyh <jonis9898@hotmail.com>
2024-08-28 17:15:57 +02:00
Kevin Papst
a19426147a added event to send email to user (#5034) 2024-08-28 14:04:36 +02:00
Kevin Papst
9d933f62c0 refactored repositories and DB queries (#5026)
* removed unused teams from export order
* added new paginator for query instead of querybuilder
* added field hydrate enums
* hide PARTIAL deprecation
* never log deprecations in production
* replaced InvoiceLoader with native Doctrine feature
* prevent excessive permission queries
* support loading customers of team
* improved findByIds
* internalized API
* fix null string deprecations
2024-08-27 10:11:19 +02:00
Kevin Papst
9e3d243b4b use enabled_locales logic to handle locales (#5017)
* allow to skip locales (here: catalan)
* use enabled_locales and replace app_locales with kimai_locales
* added test to call all reports once for super_admin
2024-08-11 17:43:20 +02:00
Kevin Papst
62047c7c01 link security guidelines on the website 2024-08-05 18:44:38 +02:00
Kevin Papst
0bcd45babe clarify test exclusions 2024-08-05 13:23:53 +02:00
Kevin Papst
2a72815481 remove invalid label 2024-08-04 19:38:47 +02:00
Kevin Papst
ff6a3e8262 Release 2.20.0 (#4987) 2024-08-04 18:22:27 +02:00
Kevin Papst
0947b88d36 added OCI docker labels (#4996) 2024-08-04 16:43:46 +02:00
Kevin Papst
5de5b4fef5 BC: Cleanup Docker tags (#4995) 2024-08-04 16:37:55 +02:00
robjuz
cde856a9c1 BC: Docker support for encoded characters in DATABASE_URL (#5000) 2024-08-04 16:02:08 +02:00
Kevin Papst
6f8877a740 new export of project overview list (#5009) 2024-08-03 00:43:05 +02:00
Kevin Papst
e7d71bff64 remove comments from XLIFF files 2024-08-02 22:43:36 +02:00
Weblate (bot)
cca0657291 Update translation files (#5010) 2024-08-02 21:49:13 +02:00
Weblate (bot)
a4904d3335 Update translation files (#5007)
Co-authored-by: Héctor Borrás <hborras@cyberclick.net>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Naoko Takano <naokomc@gmail.com>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: stuntworks <stuntworks@saber.games>
2024-08-02 21:43:29 +02:00
Kevin Papst
b9c1036b21 Revert Docker credentials urldecode (#4998) 2024-07-28 18:04:18 +02:00
Weblate (bot)
818c080d28 Translated using Weblate (#4990)
Co-authored-by: Ldm Public <ldmpub@gmail.com>
Co-authored-by: Wouter Meeusen <wouter.meeusen@outlook.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2024-07-27 17:37:10 +02:00
Weblate (bot)
a5a6ae065b Translated using Weblate (#4984)
Co-authored-by: Adrien N <adriennathaniel1999@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
2024-07-23 10:03:56 +02:00
Kevin Papst
8b06ca9d10 unify CSRF token usage in comment sections (#4986) 2024-07-23 08:33:02 +02:00
Kevin Papst
7e1025d61d fix financial year issue, fix test, improve DateTimeFactory (#4985) 2024-07-23 07:20:11 +02:00
Kevin Papst
8788311faf Release 2.19 (#4922) 2024-07-22 17:51:03 +02:00
Weblate (bot)
ce22520d7f Translated using Weblate (#4946)
Co-authored-by: Ahmad Dakhlallah <ahmad@linuxarabia.co>
Co-authored-by: Bent Haar <BentHaar@users.noreply.hosted.weblate.org>
Co-authored-by: Carlos Carreras <mytriponlinux@gmail.com>
Co-authored-by: David Bauer <dbs23.dbs23@gmail.com>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Ldm Public <ldmpub@gmail.com>
Co-authored-by: Mads R. Andersen <madsdk_789@hotmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Mikkel Ricky <rimi@aarhus.dk>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Quiwy <github@quiwy.ninja>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: geekom13 <geekom13@proton.me>
Co-authored-by: lilosti <lilosti@aarhus.dk>
Co-authored-by: ssantos <ssantos@web.de>
2024-07-20 17:36:02 +02:00
robjuz
f5d76cfd9a fix database URLs with special characters for docker (#4976) 2024-07-20 17:20:23 +02:00
Chinmay Purav
27f7f14539 fixed case of AS keyword in Dockerfile (#4943) 2024-06-29 21:45:14 +02:00
Kevin Papst
f7c32e633a bump docker action versions to fix GH deprecations 2024-06-17 11:05:49 +02:00
Kevin Papst
6d9055826f bump docker action versions to fix GH deprecations 2024-06-17 10:07:27 +02:00
Toby Batch
4627a9047e feat: stop multiarch images being lost on re tagging docker images (#4856) 2024-06-17 10:03:11 +02:00
Kevin Papst
987b46bf8f Release 2.18 (#4878) 2024-06-16 13:15:49 +02:00
Weblate (bot)
8792a1df09 Translated using Weblate (#4876)
Co-authored-by: Chan Young Park <designbycy@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Oh Wow! <kasra.hashemi1999@gmail.com>
Co-authored-by: René Bischoff <rene.bischoff@gmail.com>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: wkwkjddndjdusiq <wkwkjddndjdusiq@onionmail.com>
2024-06-16 13:02:27 +02:00
Kevin Papst
a8678892d6 yarn upgrade 2024-06-15 11:40:35 +02:00
Kevin Papst
72350b76c0 improve equality detection of same user 2024-06-15 11:40:28 +02:00
Kevin Papst
8578bbe033 improve project end handling 2024-06-13 22:31:33 +02:00
Kevin Papst
93ca983e0b invoice: do not use activity name as fallback for description (#4884)
* added replacement field description_safe
2024-06-03 19:01:40 +02:00
Kevin Papst
e29ef25581 link domains for donations 2024-05-22 14:19:11 +02:00
Kevin Papst
a617eba535 link about pages for donations 2024-05-22 14:15:42 +02:00
Kevin Papst
0c445d1bc4 Release 2.17 (#4836)
see https://github.com/kimai/kimai/pull/4836
2024-05-19 17:42:03 +02:00
Weblate (bot)
5f7114e008 Translated using Weblate (#4862)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2024-05-19 17:03:48 +02:00
Habibhaidari1
e2c511cf46 Update RateCalculatorInterface (#4851) 2024-05-17 22:55:08 +02:00
Weblate (bot)
e042ef6bfa Translated using Weblate (#4850)
Co-authored-by: Barna László <barna.laszlo@lscomputer.hu>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2024-05-12 12:41:06 +02:00
Daniel Langemann
c059e51b3c Fix typo in markdown link (#4845) 2024-05-07 09:30:33 +02:00
Kevin Papst
661bb16342 Fix hidden API token (#4828) 2024-05-03 11:38:33 +02:00
Weblate (bot)
94d6b43dcc Cleanup translation files (#4827) 2024-05-03 11:06:35 +02:00
Kevin Papst
99c296a751 Release 2.16 (#4780) 2024-05-01 14:24:24 +02:00
Weblate (bot)
8f8d228fb3 Translated using Weblate (#4826)
Co-authored-by: Bogumił Kraszewski <gogulcio@gmail.com>
Co-authored-by: Colgrave <hanqixu.blogs@simplelogin.co>
Co-authored-by: Freek <info@f3k.tech>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Nicoara Alex <alex.nicoara@yahoo.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: qeepoo <pfrade1996@protonmail.com>
2024-05-01 13:43:31 +02:00
Weblate (bot)
1214e508fe Translated using Weblate (#4814)
Co-authored-by: Bogumił Kraszewski <gogulcio@gmail.com>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: streaming s <fsrmllll1111@gmail.com>
2024-04-24 06:36:55 +02:00
Andreas Brain
7d394fbe56 added ldap-libs to for TLS certificate verification (#4802) 2024-04-23 10:33:51 +02:00
Weblate (bot)
fd4dfc6be4 Translated using Weblate (#4812)
Co-authored-by: Andre Costa <andrecaeu@gmail.com>
Co-authored-by: Balanda Nazarii <balaraz@tuta.io>
Co-authored-by: Joaquim Homrighausen <joho@boojam.se>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Julia <juliadeo@proton.me>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nicoara Alex <alex.nicoara@yahoo.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Petar Babić <petar@jesteibice.com>
Co-authored-by: SGpro <mark520fay35@gmail.com>
Co-authored-by: Tito Tapiola <ikirouta013@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: حاج حسین نجفی <hajhsynnjfy@gmail.com>
2024-04-22 18:44:21 +02:00
Kevin Papst
9dc9c71a46 added "api_access" permission for limiting API access (#4779) 2024-04-13 17:27:51 +02:00
Kevin Papst
345bb6601e fix test 2024-04-13 17:00:13 +02:00
Kevin Papst
5c8c21d609 fix menu name 2024-04-13 16:52:44 +02:00
Kevin Papst
7219b3f421 Release 2.15 (#4749) 2024-04-12 19:03:09 +02:00
Weblate (bot)
b76a5d5c35 Translations update from Hosted Weblate (#4765)
Co-authored-by: Andre Costa <andrecaeu@gmail.com>
Co-authored-by: Balanda Nazarii <balaraz@tuta.io>
Co-authored-by: Joaquim Homrighausen <joho@boojam.se>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Julia <juliadeo@proton.me>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Petar Babić <petar@jesteibice.com>
Co-authored-by: Tito Tapiola <ikirouta013@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Kevin Papst <kevinpapst@users.noreply.github.com>
2024-04-12 16:22:17 +02:00
Kevin Papst
40a9027d34 try v5 without discussion 2024-04-06 11:09:02 +02:00
Kevin Papst
553bd20e06 internal: bump versions due to node16 deprecation 2024-04-06 10:33:53 +02:00
Kevin Papst
3ea5803e08 revert to @v4 2024-04-06 10:29:15 +02:00
Kevin Papst
4949afb098 try different token 2024-04-06 10:28:27 +02:00
Kevin Papst
d328badca1 enable debug 2024-04-06 10:26:47 +02:00
Kevin Papst
175d371ef9 change name 2024-04-06 10:17:12 +02:00
Kevin Papst
6bb7b38252 bump version 2024-04-06 10:15:56 +02:00
Kevin Papst
afe0656502 added API tokens, deprecate API passwords (#4637) 2024-04-05 23:51:16 +02:00
Kevin Papst
dd51c8dfba utilize UserService for SAML (#4748) 2024-04-05 19:22:13 +02:00
Kevin Papst
b6c98f871d Release 2.14 (#4710)
- show "link has expired message" in password reset screen
- added date objects as hydrator variables - for custom date formats in invoice templates
- show meta-fields with null values (e.g. booleans with `false` where hidden)
- fix permission check: allow to remove `view_own_timesheet` but still record times
- prevent error 500 if customer country is empty
- fix API 500 error if project does not exist when creating new timesheet
- fix tags are not created in remote-search mode
- do not check "export items" by default
- fix daterange query, if user an request locale are different
- added logging for invalid SAML responses (see various discussions)
2024-04-05 12:38:21 +02:00
Weblate (bot)
19b2d47591 Translated using Weblate (#4746)
Co-authored-by: Joaquim Homrighausen <joho@boojam.se>
Co-authored-by: Jose Delvani <delvani.eletricista@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
2024-04-04 17:50:23 +02:00
Kevin Papst
a636683dee Configurable activity and project number (#4729)
* added configurable activity number
* added configurable project number
* fix deprecations
* added some tests for entity exporter
* better configuration of dropdown pattern for customer, project and activity
2024-04-04 17:43:22 +02:00
Kevin Papst
c1f5d3def4 do not export items by default 2024-04-04 17:35:43 +02:00
Kevin Papst
3e88a007d0 allow to change locale in DateRangeType 2024-04-04 17:35:16 +02:00
Kevin Papst
1fdd11e94c link to wall of love 2024-04-04 00:20:31 +02:00
Toby Batch
2ac783a300 split docker to use base image for faster builds (#4586) 2024-04-02 17:50:24 +02:00
Weblate (bot)
3a358b1434 Translated using Weblate (#4722)
Co-authored-by: Jean-Michel <arsene_lupin_57@hotmail.fr>
Co-authored-by: Joaquim Homrighausen <joho@boojam.se>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Thanh <pancakes21f@gmail.com>
2024-04-02 01:06:57 +02:00
Yannik Beaulieu
216da19cc9 Add support for negative durations in All Users reports (#4717) 2024-03-27 23:57:52 +01:00
Kevin Papst
dee90bb15e Release 2.13 (#4659) 2024-03-10 15:35:59 +01:00
Weblate (bot)
a78e8ed8c4 Translated using Weblate (#4693)
Co-authored-by: Andre Costa <andrecaeu@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2024-03-10 15:29:27 +01:00
Weblate (bot)
e293d62aa1 Translated using Weblate (#4658)
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: DOHEX <xuyaohui617@outlook.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Сергій <sergiy.goncharuk.1@gmail.com>
2024-02-22 18:00:51 +01:00
Kevin Papst
f016221e8e Fixes for 1.12 (#4655)
* fix missing locales
* bump composer packages
* changed translations
* assert timezone on customer
* include user accountNumber in excel export
* improve next customer number calculation
* fix z-index of contextmenu / action dropdown
2024-02-22 13:03:09 +01:00
Kevin Papst
36c578452e show top nav links as buttons (#4633) 2024-02-12 17:50:22 +01:00
Kevin Papst
6e643ee99c revert to classical bootstrap form layout (#4632) 2024-02-12 17:35:30 +01:00
Kevin Papst
58cbf1776f Weekly hours improvements (#4631)
* fix table padding
* reduced minimum quick-entry recent activity row amount
* use activity favorites in weekly hours
2024-02-12 14:20:17 +01:00
Kevin Papst
85a16a9363 Release 2.12 (#4609) 2024-02-07 23:47:25 +01:00
Kevin Papst
7abe787778 added project filter in user-list reports (#4615) 2024-02-07 18:00:29 +01:00
Weblate (bot)
e98732f44a Translated using Weblate (#4614)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
2024-02-06 16:06:40 +01:00
Kevin Papst
c2afebbb5e Fix Doctrine deprecations (#4608) 2024-02-02 15:48:11 +01:00
Kevin Papst
49e69d1ae3 Release 2.11 (#4580) 2024-02-02 13:52:24 +01:00
Andreas Brain
a9a32c83ac Add library to re-enable TLS certificate verification for LDAP connections (#4598) 2024-02-02 13:46:40 +01:00
Weblate (bot)
64fa67f15d Translated using Weblate (#4587)
Co-authored-by: Alex Terlan <terlan2012@gmail.com>
Co-authored-by: Bruno Paré-Simard <bruno.p@brunops.com>
Co-authored-by: Bálint László <blaszlobors@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: abdelbasset jabrane <ribago9317@cubene.com>
Co-authored-by: delvani <inavleb@users.noreply.hosted.weblate.org>
2024-02-02 13:44:25 +01:00
Kevin Papst
df3ca9d5a9 Split user language (UI translation) from locale (formatted values) (#4595) 2024-01-30 00:09:53 +01:00
Kevin Papst
12ef19df28 support default time on date-time-picker (#4579) 2024-01-21 01:59:30 +01:00
Kevin Papst
a5b4a92086 new phpstan version 2024-01-21 00:28:03 +01:00
Kevin Papst
3aaaf9ffc0 bump packages 2024-01-20 02:12:26 +01:00
Weblate (bot)
3f73f2c570 Translated using Weblate (#4576)
Co-authored-by: Bálint László <blaszlobors@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Saveliy <jitropolit@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2024-01-20 01:27:25 +01:00
Kevin Papst
46739795ff Release 2.10 (#4549) 2024-01-19 12:05:07 +01:00
Kevin Papst
afd60a67f6 merged and removed small translation files (#4572)
* merged about with messages
* merged invoice-numbergenerator with messages
2024-01-16 23:39:13 +01:00
Weblate (bot)
bb325888a1 Translated using Weblate (#4551)
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Miloš Havlíček <milos.havlicek@cothema.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: albanobattistella <albano_battistella@hotmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: сэр Аноним <mcptminei@gmail.com>
2024-01-16 23:16:46 +01:00
Kevin Papst
fdda9841fa allow to edit username (#4559) 2024-01-14 13:02:44 +01:00
Ronald Derksen
5acd33dd64 Make 'pagebreak' optional in pdf layout exporter (#4561) 2024-01-13 14:44:31 +01:00
Kevin Papst
6531e7fe52 Release 2.9.0 (#4526)
* added fix to work around bc break in new phpword version
* fix phpoffice deprecations
* mark unused option as deprecated
* support for DateTimeInterface and DateTimeImmutable where possible
* use TRUSTED_PROXIES setting - fixes #4533
* re-enable Kimai test in docker test build script (#4541)
* bump dependencies
2024-01-10 12:43:07 +01:00
Weblate (bot)
c6a651456e Translated using Weblate (#4531)
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: yangyangdaji <1504305527@qq.com>
Co-authored-by: Сергій <sergiy.goncharuk.1@gmail.com>
2024-01-09 23:53:56 +01:00
Kevin Papst
8eeb9c120a Release 2.8.0 (#4508) 2024-01-03 00:28:35 +01:00
Janne Heß
d8f89d9f3d release-drafter: adapt supported PHP versions (#4512) 2024-01-03 00:25:24 +01:00
Simon Schaufelberger
26a89725eb fix wrong default protocol for customer homepage (#4514) 2024-01-02 15:20:24 +01:00
Weblate (bot)
9f0165ef4d Translated using Weblate (#4517)
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: Сергій <sergiy.goncharuk.1@gmail.com>
2024-01-01 21:05:29 +01:00
Kevin Papst
3d0a35f0cd bump checkout action version 2023-12-27 02:10:46 +01:00
Kevin Papst
c5dcf9e0fd replace deprecated set-output with environment usage, deactivate broken test-lite 2023-12-26 17:18:08 +01:00
Kevin Papst
ad645f5b58 Release 2.7.0 (#4506)
* added api URL for simpler integration
* allow to request password change upon next login
* make ModifiedAt timesheet independent
* improved plugin api
* replace kernel calls with AutoconfigureTag and TaggedIterator attributes
* new translation keys (e.g. for days)
* support setting min and max date on date and daterange pickers
2023-12-26 14:49:11 +01:00
Weblate (bot)
f86eca05ae Translated using Weblate (#4507)
Co-authored-by: Alan Aparecido da coneicao <alanaparecidodaconeicao@gmail.com>
Co-authored-by: Balanda Nazarii <balaraz@tuta.io>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nikolay Soloshin <nigiriits@users.noreply.hosted.weblate.org>
Co-authored-by: Petal <Petalzu@outlook.com>
Co-authored-by: Thomas <jzh20180312@163.com>
Co-authored-by: Vipul Hangadiya <hangadiyavipul@gmail.com>
Co-authored-by: Wei-Cheng Yeh (IID) <iid@ccns.ncku.edu.tw>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2023-12-26 01:32:18 +01:00
Kevin Papst
ac2a6ba2c8 use a full mysql database URL as default (#4504) 2023-12-25 23:41:13 +01:00
Christian Schupfner
e23d0474fd Upgrade Docker to PHP 8.2 (#4476)
- base image changed to PHP 8.2
- base images changed to bookworm
- libicu63 upgraded to libicu72
2023-12-17 17:05:38 +01:00
Kevin Papst
2edcbcca50 sort invoice items by date before passing to template (#4495) 2023-12-17 16:50:47 +01:00
Kevin Papst
5f4b6d3cfa Release 2.6.0 (#4472)
- Added: calendar entry title combination for customer, project and activity
- Added: show not_invoiced and not_exported data in detail screens
- Added: force logout if user is disabled
- Added: reduced amount of database queries on several screens
- Fixed: open-close status on work-contract screen for users without configuration
- Fixed: failsafe order/orderBy in query if manually manipulated to be null
- Fixed: unify statistic calculation (not_invoiced and not_exported) across screens
- Tech: bump packages
- Tech: Symfony 6.4
2023-12-17 16:19:50 +01:00
Kevin Papst
af82fd040d removed deprecated test script (#4490) 2023-12-14 12:12:17 +01:00
Kevin Papst
e0769bc3dc allow PHP 8.3 (#4471)
Fix use of range() and auto-width columns for Excel exports
2023-12-01 22:40:02 +01:00
Weblate (bot)
8fd2e7029e Translated using Weblate (#4466)
Co-authored-by: EngageIndo <engageindo@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Shimpei <sfutami0821@gmail.com>
Co-authored-by: albanobattistella <albano_battistella@hotmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: nigiriits <i79046290200@gmail.com>
Co-authored-by: nigiriits <nigiriits@users.noreply.hosted.weblate.org>
Co-authored-by: xorly <patrikbachan@gmail.com>
2023-12-01 22:38:32 +01:00
Kevin Papst
f570b5506a added missing translations 2023-12-01 18:33:09 +01:00
Kevin Papst
0e1bd818bf bump packages 2023-12-01 16:42:51 +01:00
Kevin Papst
02bcd45116 Release 2.5.0 (#4454)
- added command to list users
- corrected wrong german translation
- work contract validations
- prevent error with missing params
- use collapsible, minor UI improvement
- added classes to target menu buttons in custom rules
- disable webpack notifier, incompatible with mac arm
- use explicit menu service to generate menu
- bump to fontawesome 6 and replace restart icon
- change repeat icon for recent activities
- moved user bookmarks (favorites) to top nav
- fix totp seconds window (leeway)
- new migration to fix remaining user preferences with dots in name
- remove duplicate named column in user screen
- unify and added translations
- added missing filter and tags to InvoiceSecurity
2023-12-01 11:38:17 +01:00
Kevin Papst
16d4a691f8 Fix LDAP with internal users (#4453)
* added logging, in case Laminas libs are not available
* make sure that internal users can still login if LDAP is activated
2023-11-20 21:33:36 +01:00
Kevin Papst
ecded0a065 added activity overview report 2023-11-19 16:10:32 +01:00
Kevin Papst
20164295f8 Release 2.4.0 (#4427)
* button to duplicate old timesheets, even those from lockdown period
* bump composer packages
* fixes tooltip remains in view #4426
* fix js error if all widgets were removed
* allow to open timesheet edit dialog from export listing
* css classes for timesheet context menu, so they can be hidden
* added flag to force a user to set password upon login
* enable lazy-ghost-objects to fix deprecation
* change user, username, internal_rate export column labels
* helper method to find user by displayname
* log improvements and format changes
* deactivate broken schema validation
2023-11-19 16:05:43 +01:00
Weblate (bot)
9d8e5ecd7a Translated using Weblate (#4447)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Matti O <matt1@users.noreply.hosted.weblate.org>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Patrick Kartschewski <weblate@patrick-kartschewski.de>
Co-authored-by: Reza Almanda <rezaalmanda27@gmail.com>
Co-authored-by: Victor Hitriy <pvnhome@yandex.ru>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: albanobattistella <albano_battistella@hotmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2023-11-19 16:01:35 +01:00
Kevin Papst
8a1059fdd1 added docker build and publish workflow (#4446) 2023-11-17 14:37:32 +01:00
Kevin Papst
92c6922afb fix LDAP issues and allow to migrate from local to LDAP account (#4445) 2023-11-17 14:37:00 +01:00
Kevin Papst
2fb9ea9239 bump packages 2023-11-17 13:22:50 +01:00
Toby Batch
350875be2a moved dockerfile to main repo (#4393) 2023-11-17 13:07:51 +01:00
Kevin Papst
6a828cc9bd Release 2.3.0 (#4412)
- move user-preferences to edit submenu
- unify user preferences with other forms
- use light fieldset for all user-edit-forms
- support offcanvas elements
- allow to dynamically inject toolbar buttons (via plugins)
- use interface for formatting dates
- improve docker issue template
- bump version and composer packages
2023-11-08 22:30:22 +01:00
Weblate (bot)
7034066de9 Translated using Weblate (#4346)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Benjamin Alan Jamie <benjamin@weblate.org>
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Den SE <dense800@gmail.com>
Co-authored-by: EngageIndo <engageindo@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Liam Azofra <liamazofra@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Prefill add-on <noreply-addon-prefill@weblate.org>
Co-authored-by: Serhii Horichenko <m@sgg.im>
Co-authored-by: Singh <spamio@protonmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: albanobattistella <albano_battistella@hotmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: yangyangdaji <1504305527@qq.com>
Co-authored-by: مهدی امیری راد <mahdiamererad@gmail.com>
2023-11-07 12:41:57 +01:00
Kevin Papst
2a9bdb7982 fix locale definitions starting with AM/PM (#4408)
* adapt locale script to fix locales starting with AM/PM
* fix korean locales that start with AM / PM
* added missing uk and zh_Hant locales
2023-11-07 12:27:11 +01:00
Kevin Papst
a1d9874c13 added role cards to permission screen (#4401)
* simplify creating new roles by auto-replacing input
2023-11-04 20:17:05 +01:00
Kevin Papst
0b1625175b remove link to external docker repo 2023-11-03 00:06:19 +01:00
Kevin Papst
0f6a6e7561 Update docker.yml (#4395) 2023-11-03 00:05:21 +01:00
Kevin Papst
7bbd497ef1 change URL to support landing page 2023-11-02 23:55:42 +01:00
Kevin Papst
0b3f645bda added docker bug report template 2023-11-02 23:54:29 +01:00
Kevin Papst
c840fee911 Release 2.2.1 (#4389)
* added missing functions to invoice security policy
2023-11-01 01:16:17 +01:00
Simon Schaufelberger
e06acc95c5 add parameter types and fix a phpstan issue (#4384) 2023-10-31 17:03:26 +01:00
Kevin Papst
95f15e6c88 Release 2.2.0 (#4359)
* deactivate deprecation logging in prod for now
* fix several deprecations
* enable CSRF for logout
* allow more twig methods and functions in InvoiceSecurity policy
2023-10-31 16:41:09 +01:00
Kevin Papst
114617a052 clarify EOL of Kimai 1 2023-10-20 16:30:20 +02:00
Kevin Papst
38e37f1c2e Release 2.1.0 (#4321)
* fix deprecations
* remove unused config
* replace invalid annotation type with attribute
* use AsDoctrineListener to fix deprecation
* new ModifiedSubscriber to support custom logic and fix deprecation
* removed inheritdoc comment
* new ModifiedSubscriber to support custom logic and fix deprecation
* cleanup event dispatcher interface
* re-order annotation params
* one more doctrine based deprecation
* fix query to count active timesheets
* link to "all times" to identify active timesheets
* link icon instead of text
* fix "skin" translation in wizard
* use duration filter to show duration
* added login link command and controller
* bump tabler theme to 1.0
* added wizard to force password reset by user
* allow to configure that new accounts need to reset their password
* prevent uploading twig templates by default
* bump composer packages
* enable sandbox and basic security measures for custom twig templates for invoice and export
* bump to symfony 6.3.5
* allow to export single user reports to excel
* removed broken method to reload twig cache
* added api parameter to fetch user collection fully serialized
* allow to replace or append description via timesheet batch update
* show api username above form
2023-10-19 11:21:50 +02:00
Kevin Papst
7a5b12762a Release 2.0.35 (#4302) 2023-09-23 18:15:22 +02:00
Kevin Papst
de419350b2 Release 2.0.34 (#4281) 2023-09-17 22:32:01 +02:00
Weblate (bot)
a6b237936e Translated using Weblate (#4282)
Co-authored-by: Kieran W <alarmcuddly@outlook.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Mykola Skira <mykola.skira@icloud.com>
Co-authored-by: No Pasaran <damiengourdin@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
Co-authored-by: Łukasz Kosiński <lukikosin@gmail.com>
2023-09-11 23:18:07 +02:00
Kevin Papst
6e1207578e Release 2.0.33 (#4273)
* added function to check if meta-field is defined by a plugin
* hide un-defined meta-fields in details view
* fix default charset = utf8mb4
* remove broken DATABASE_VERSION fallback
* split off upgrade infos for version 1.x
* fix page out of range #4279
2023-09-07 22:24:08 +02:00
Kevin Papst
31348da4c0 Release 2.0.32 (#4256) 2023-08-31 15:33:53 +02:00
Bruno Paré-Simard
452de88e18 change isWeekend() handling to use work-hour configuration (#4261) 2023-08-31 13:38:58 +02:00
Weblate (bot)
18d953e79b Translated using Weblate (#4267)
Co-authored-by: Ali Evcil <evcil@proton.me>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
2023-08-31 12:51:37 +02:00
Kevin Papst
636422e342 show global form errors - fixes #4233 2023-08-21 20:38:32 +02:00
Weblate (bot)
20149ae765 Translated using Weblate (#4252)
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2023-08-21 20:31:38 +02:00
Kevin Papst
a392f61d61 Release 2.0.31 (#4245)
* replace strings by class references
* allow 64 chars for username
* fix time can be optional and null
* fix timezone is not respected
* bump version
* fix br in attribute
* support different visible duration from booked duration
* fix image URL
2023-08-21 20:24:24 +02:00
Kevin Papst
3e61e0dce6 added supervisor setting for user (#4251) 2023-08-20 13:18:35 +02:00
Kevin Papst
9baa477bed fix payload 2023-08-17 22:58:28 +02:00
Kevin Papst
4d182ad1a7 validate version 2023-08-17 22:54:35 +02:00
Kevin Papst
e77056c4b7 fix payload and validate version 2023-08-17 22:22:53 +02:00
Johannes Przymusinski
d7f1df2987 update website version automatically (#4248) 2023-08-17 21:16:36 +02:00
Kevin Papst
8c1a793b0a added workflow to update website version 2023-08-16 22:33:25 +02:00
Kevin Papst
adc0779912 Release 2.0.30 (#4225) 2023-08-16 18:20:14 +02:00
Weblate (bot)
c7bc8fae73 Translated using Weblate (#4210)
Co-authored-by: Evgeniy Khramov <thejenjagamertjg@gmail.com>
Co-authored-by: Joaquim Homrighausen <joho@boojam.se>
Co-authored-by: John Aleksander Jazbec <johnny@xhorizont.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Matthew Durajka <logrcz@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: PatoGordo <icariusv@gmail.com>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Serhii Horichenko <m@sgg.im>
Co-authored-by: Tobs Hart <tobias@2bproduction.net>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Yaroslaw <bruce.levitangens@gmail.com>
Co-authored-by: beq <beqbdean@gmail.com>
Co-authored-by: full name <iaeqgz09gu6d@opayq.com>
Co-authored-by: jhtm <jhtm@users.noreply.hosted.weblate.org>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-08-16 15:08:22 +02:00
Kevin Papst
0a0ffb4ac9 remove text from tag choice after selection - fixes #4076 2023-08-04 13:03:11 +02:00
Kevin Papst
b831532323 Release 2.0.29 (#4178)
- show button title if delete is used in page actions
- fix invoice due date depends on invoice date, replace DateTime with DateTimeI… 
- lowercase all font names in PDFs, otherwise they fail loading
- hide empty fieldset (work-contract page)
- activate contract_other_profile by default for admin and super-admin
- deactivate rule to check "maximum duration of entries" by default
- allow to deactivate presets in DateRange Picker (for Devs)
2023-07-26 15:16:59 +02:00
Kevin Papst
385753fbc3 Release 2.0.28 (#4172)
See https://github.com/kimai/kimai/pull/4172
2023-07-09 15:27:27 +02:00
Kevin Papst
651f812da8 Release 2.0.27 (#4107) 2023-07-04 17:01:29 +02:00
Weblate (bot)
6a99ad41ca Translated using Weblate (#4109)
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Matthew Durajka <logrcz@gmail.com>
Co-authored-by: Matúš Bulla <matbull12345@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: SC <lalocas@protonmail.com>
Co-authored-by: Sergii Horichenko <m@sgg.im>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Yonggen <vizualizer@gmail.com>
Co-authored-by: bigvictorio <bigvictorio12345@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-07-04 00:17:38 +02:00
Kevin Papst
dd89363c72 Improve UX for invoice template management (#4121)
change translations and to explain that calculator actually group items by fields
2023-06-21 08:17:54 +02:00
Weblate (bot)
983bf2c88b Translated using Weblate (#4099)
Co-authored-by: Arjan Houben <arjan@houben.es>
Co-authored-by: Jiri Nakola <github@nakola.fi>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Sebastiaan <djsebas@home.nl>
Co-authored-by: Tomas Koutek <spam@hug0.cz>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: akawshi <zenranoakawshi@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-06-13 14:17:37 +02:00
Kevin Papst
ce7fe67fcc use modern flat form styles with more icons (#4098) 2023-06-09 19:16:36 +02:00
Kevin Papst
053a1d9017 use collapsible element instead of collapsible card (#4096) 2023-06-09 18:17:32 +02:00
Kevin Papst
2e2bf986a4 Support visibility for tags (#4086) 2023-06-09 17:07:49 +02:00
Kevin Papst
6e781b59e2 Release 2.0.26 (#4087)
- setting "rounding days" not required
- developer: added user pref for public holiday group (to be used by plugins)
- developer: added WorkingTimeYearEvent (to be used by plugins)
- user pref: cleanup work contract form and support more fields (to be used by plugins)
- code cleanup
- bump theme and composer packages
2023-06-09 16:29:19 +02:00
Kevin Papst
0663995d06 Release 2.0.25 (#4066)
* added support for hourly rate column in detail table
* allow to register icon in extension
* allow to show QR code secret
* new translations
* bump theme and packages
* fix validation for invoice-document-filenames with uppercase character
* max upload size 1MB
* fix last month in daterange-picker in certain situations, more years in quick-select
* remove unused package-versions-deprecated
* link preferences from contract warning message
* added page_setup page layout
* prevent DROP TABLE in addSQL() and replace drop table with schema call
* added azuyalabs/yasumi
2023-06-06 23:05:20 +02:00
Kevin Papst
2ba9cff281 bump theme to get navigation id specific classes (#4065) 2023-05-26 22:39:07 +02:00
Kevin Papst
9c1150c50e added JS api to access current user in frontend (#4064) 2023-05-26 18:40:54 +02:00
Kevin Papst
b4a4d81ca8 Fix nullable parameter in work-contract API (#4063) 2023-05-26 18:39:44 +02:00
Kevin Papst
2681b81990 calendar: update popover content when shown (#4045) 2023-05-22 18:41:30 +02:00
Kevin Papst
97092acae9 fix single dropdown became two lines (#4041) 2023-05-21 17:49:44 +02:00
Kevin Papst
fdb6cf5cf8 allow to remove date from non-required field (#4040) 2023-05-21 17:13:41 +02:00
Kevin Papst
7ab0a8cea1 dynamic favicon that indicates if an entry is running (#4038) 2023-05-21 15:40:45 +02:00
Kevin Papst
2664d6117f show available github release only if newer version exists (#4037) 2023-05-20 13:49:31 +02:00
Kevin Papst
6bdf27fc9b change parameter name 2023-05-20 12:46:16 +02:00
Weblate (bot)
f0298335ee Translated using Weblate (#4036)
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Sabri Ünal <libreajans@gmail.com>
Co-authored-by: Sebastiaan <djsebas@home.nl>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
2023-05-20 12:08:36 +02:00
Kevin Papst
a58a33fc7d Release 2.0.22 (#4032)
* fix version string in migration
* disable search in order and order_by
* reduce divider spacing for context menu and select with optgroup
2023-05-20 12:08:01 +02:00
Kevin Papst
9bd5965ecd Release 2.0.21 (#4030)
* increase padding in wizard
* fix theme chooser in wizard
* improve dynamic export columns in PDFs
* added label for total column
* bump theme bundle
* improve avatar list spacing
* be more flexible parsing times - fixes #4031
2023-05-17 15:02:10 +02:00
Kevin Papst
29624354a2 Release 2.0.20 (#4028)
* max duration per entry increased from 8 to 10 hours
* fixes #3981 - clickable area in dropdown too small
* fixes #4008 - duplicate activities in project-details report
* headers and summary styling in project-details report
* show billable stats in project-details report
* added new invoice variable for entry.duration_format
2023-05-15 22:30:37 +02:00
Kevin Papst
04422f3530 frontend update to tabler beta 19 (#4029) 2023-05-15 19:10:00 +02:00
Kevin Papst
43bd7bf1ab added API for handling work contract times (#4016) 2023-05-13 01:24:15 +02:00
Kevin Papst
4b2a3669e6 Release 2.0.19 (#4022)
* prevent invoices with exceeding filename
* fixed invalid LDAP log level
* support locale switching in action events
2023-05-12 14:45:51 +02:00
Kevin Papst
1099e76244 Release 2.0.18 (#4003)
* prevent too long values for user preferences
* add chart value 0 to y-axis if last value > 0, to always display the zero line (project details)
* add user-preferences to invoice hydrator
* DateTime vs DateTimeInterface
* simplify permission config
* fix query for teamleads limiting to only selected teams not possible
2023-05-08 17:11:55 +02:00
Weblate (bot)
d8f72b8b88 Translated using Weblate (#4010)
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Hama Czech <hamaczech13@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Mæve Rey <martin.rey@mailbox.org>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Sanji Finsmok <khldeilamil@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-05-08 13:07:59 +02:00
Weblate (bot)
b2314de315 Translated using Weblate (#4002)
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
2023-05-02 00:44:49 +02:00
Kevin Papst
66413d789c Release 2.0.17 (#3992)
* prevent empty title for select options
* removed css for unused sweetalert
* fix isWeekend() check with DateTimeInterface
* reset timesheet rates on "create copy"
* wrap long names in multi-selects - fix #4001
* rename profile menus
* show all possible links in user profile dropdown
* check if plugin is compatible before displaying the buy link
2023-05-02 00:40:43 +02:00
Kevin Papst
7112e932a2 Allow 2FA for SAML and LDAP users (#4000)
* inline totp image as data uri to prevent caching issues
* allow 2fa for ldap and saml users
* allow 2FA access for super admin to all profiles
2023-05-01 08:28:35 +02:00
Kevin Papst
01e26dca9e Release 2.0.16 (#3990)
https://github.com/kimai/kimai/pull/3990
2023-04-27 18:48:31 +02:00
Weblate (bot)
844062b90e Translated using Weblate (#3991)
Co-authored-by: Anders Johansson <johansson@aljmedia.se>
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Eryk Michalak <gnu.ewm@protonmail.com>
Co-authored-by: Petr Daniel Ambrož <paces@paces.cz>
2023-04-27 18:22:01 +02:00
Kevin Papst
f60065d089 split timesheet validator to simplify imports (#3974) 2023-04-27 13:56:07 +02:00
Kevin Papst
046ed313c9 Release 2.0.15 (#3970) 2023-04-16 00:44:00 +02:00
Weblate (bot)
ecd8ee85f3 Translated using Weblate (#3968)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Kyotaro Iijima <kyotaro.eyes@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: tachyglossues <tachyglossues@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-04-06 22:03:33 +02:00
Kevin Papst
0c397e5080 Release 2.0.14 (#3963)
- show customer totals in single-user reports
- support custom fonts in export / invoice templates
- require daterange for export and invoice searches
- improve help label for user locale
- show decimal formats in help controller
- cache tag amount per request
- composer updates
- improved code styles
- added default label to date picker
- new macros & use own macro
2023-04-05 19:14:49 +02:00
Kevin Papst
01226a1243 Release 2.0.13 (#3955)
- added missing escape to prevent HTML injection
- added missing color attribute
- upgrade theme
  - use dropdown submenu if title is set, otherwise dropdown tends to get too long
  - allow to use card-table instead of card-body
  - added `required` attribute to username and password field
- fix pagination back to page 1
- prevent tag name too long
- re-add missing user preferences link
2023-03-30 01:08:15 +02:00
Weblate (bot)
7164ec126f Translated using Weblate (#3945)
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: gnu-ewm <gnu.ewm@protonmail.com>
Co-authored-by: tachyglossues <tachyglossues@gmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-03-30 01:06:24 +02:00
Kevin Papst
04b5eb4c38 Release 2.0.12 (#3947)
- added submenus in action drodowns, to shorten them
- show all user-edit-screens in action dropdown
- fix cascade delete teams through customer
- fix cascade delete customer/project/activity through teams
- fix responsive classes for "internal rate" column
- clarify error message if invoice number generator or calculator is missing
2023-03-24 00:47:36 +01:00
Kevin Papst
3a5d7a62de Release 2.0.11 (#3932)
- added "today" as selector in date-range dropdown
- added feature to prevent auto-select of dropdowns with only one entry
- added hint that no changes were detected in batch update
- added negative invoice sums are possible (e.g. for credit notes)
- fix project list is expanded after submission
- fix invalid date parsing causes 500
- fix: prevent auto-select of activities in export and invoice form (in case only one global activity exists)
- fix team assignments for customer and project were not saved (using API now)
- fix form fieldset with legend styling (e.g. team project assignment)
- fix required meta-field were forced to have a value in batch update
- fix tomselect meta-field was not disabled in batch update
- fix unset internal rate is shown as 0
- fix one minute rounding problem in duration-only mode  with "now" being default time
- fix column width and label for duration-only mode
- tech debt: cleanup invoice template (remove invoice layout)
- tech debt: reorder for simpler comparison with invoice form
- possible BC for devs: remove unused methods from form trait
- bump composer packages (includes new translations for auth screens)
2023-03-21 12:42:18 +01:00
Weblate (bot)
252652082d Translated using Weblate (#3937)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: Blueberry <igory.ygr200@gmail.com>
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Jeffrey <kjw5608kjw@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Lars Vogdt <lars.vogdt@suse.com>
Co-authored-by: Ondřej Mach <machondra2003@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Tang Yin <bingyuanshiye@126.com>
Co-authored-by: Viktor Kryvda <ivic4u@gmail.com>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: tygyh <jonis9898@hotmail.com>
2023-03-18 22:06:36 +01:00
Kevin Papst
f007697a73 Release 2.0.10 (#3927)
* allow API calls via GET
* allow to stop timesheet via GET
* improve form handling and validation
* improve stop button handling
* bump version
2023-03-15 23:02:28 +01:00
Kevin Papst
1a8c78944a Release 2.0.9 (#3922)
* fix api definition
* include customer number in validation message
* fix doctrine deprecation, prepare for DBAL 4
* added DataSubscriberInterface to identify certain doctrine subscribers
2023-03-14 23:51:49 +01:00
Kevin Papst
8449eafcb6 Release 2.0.8 (#3914)
* support parsing negative durations in JS
* bump luxon dependency
* make sure that 2FA is not required for session based API calls
* show name of items to delete
* fix permission issue for recent activity items
2023-03-13 01:48:53 +01:00
Kevin Papst
1310285133 bump version 2023-03-08 23:30:45 +01:00
Weblate (bot)
588e85d48f Translated using Weblate (#3905) 2023-03-08 21:05:19 +01:00
Kevin Papst
aebd57e311 added translation domain for dashboard widgets (#3909) 2023-03-08 19:01:49 +01:00
Kevin Papst
9d503300f6 Release 2.0.6 (#3900)
* cleanup invoice templates
* cleanup invoice translations
* fix invoice datetime for now
* support invoice archive order by number and status
* bump version
* allow meta-field sub-classing
* removed unused translation task.delete
* prevent null in str_replace
2023-03-08 00:38:10 +01:00
Weblate (bot)
80f8f70695 Translated using Weblate (#3902)
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Jeffrey <kjw5608kjw@gmail.com>
Co-authored-by: Kevin Papst <kevin@kevinpapst.de>
Co-authored-by: Ondřej Mach <machondra2003@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Wellington Terumi Uemura <wellingtonuemura@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2023-03-07 21:39:42 +01:00
Weblate (bot)
c6fc06222f Unify language files (#3899)
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: Kevin Papst <kpapst@gmx.net>
2023-03-05 15:23:18 +01:00
Weblate (bot)
8926f7677e Update translation files (#3898) 2023-03-05 04:40:00 +01:00
Weblate (bot)
517e7eae89 Update translation files (#3897) 2023-03-05 04:38:12 +01:00
Weblate (bot)
8b53980ce7 Update translation files (#3896) 2023-03-05 04:36:34 +01:00
Weblate (bot)
d13083fc6f Cleanup translation files (#3895) 2023-03-05 04:34:54 +01:00
Weblate (bot)
34a79b1e3a Translated using Weblate (#3894)
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
2023-03-05 03:52:28 +01:00
Weblate (bot)
ea8bf6d1fa Cleanup translation files (#3893) 2023-03-05 03:48:04 +01:00
Weblate (bot)
cc39f25d37 Update translation files (#3887)
Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Co-authored-by: Dan <denqwerta@gmail.com>
Co-authored-by: Felipe Nogueira <contato.fnog@gmail.com>
Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Co-authored-by: Luna Jernberg <droidbittin@gmail.com>
Co-authored-by: Massimo Pissarello <mapi68@gmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Ondřej Mach <machondra2003@gmail.com>
Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Co-authored-by: Simona Iacob <s@zp1.net>
Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Co-authored-by: i3sey <deniskedrovsky@mail.ru>
Co-authored-by: tygyh <jonis9898@hotmail.com>
Co-authored-by: yangyangdaji <1504305527@qq.com>
2023-03-05 03:44:28 +01:00
Kevin Papst
0cbf0053d2 Release 2.0.5 (#3888)
- Fixed: mandatory fields / form validation for invoice template
- Added: Duration as calendar title replacer (open: running records)
- Fixed: HTML injection in Calendar
- Fixed: Doctrine Proxies are not initialized (leads to empty customer/project)
- Fixed: tag creation
- Fixed: validation errors do not need to be logged in prod
- Removed: Customer VCard download, as used library is outdated and not maintained
- Added: supporting translations domains in many new places (menu, help_text, page_setup, report, exporter, calendar)
2023-03-05 03:08:43 +01:00
Kevin Papst
3b93afabc8 Revert "bump packages"
This reverts commit d03fbf0ef9.
2023-03-02 15:15:01 +01:00
Kevin Papst
d03fbf0ef9 bump packages 2023-03-02 15:10:23 +01:00
1969 changed files with 59013 additions and 39929 deletions

20
.docker/000-default.conf Normal file
View File

@@ -0,0 +1,20 @@
<VirtualHost *:8001>
ServerAdmin webmaster@localhost
DocumentRoot /opt/kimai/public
PassEnv MAILER_FROM
PassEnv APP_ENV
PassEnv APP_SECRET
PassEnv DATABASE_URL
PassEnv MAILER_URL
PassEnv TRUSTED_PROXIES
<Directory "/opt/kimai/public">
Require all granted
DirectoryIndex index.php
AllowOverride All
</Directory>
</VirtualHost>
ServerName localhost

52
.docker/dbtest.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
$DATABASE_HOST = urldecode($argv[1]);
$DATABASE_BASE = urldecode($argv[2]);
$DATABASE_PORT = $argv[3];
$DATABASE_USER = urldecode($argv[4]);
$DATABASE_PASS = urldecode($argv[5]);
echo "Testing DB:";
try {
$pdo = new \PDO("mysql:host=$DATABASE_HOST;dbname=$DATABASE_BASE;port=$DATABASE_PORT", "$DATABASE_USER", "$DATABASE_PASS", [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
]);
} catch(\Exception $ex) {
switch ($ex->getCode()) {
// we can immediately stop startup here and show the error message
case 1045:
echo 'Access denied (1045)';
die(1);
// we can immediately stop startup here and show the error message
case 1049:
echo 'Unknown database (1049)';
die(2);
// a lot of errors share the same meaningless error code zero
case 0:
// this error includes the database name, so we can only search for the static part of the error message
if (stripos($ex->getMessage(), 'SQLSTATE[HY000] [1049] Unknown database') !== false) {
echo 'Unknown database (0-1049)';
die(3);
}
switch ($ex->getMessage()) {
// eg. no response (fw) - the startup script should retry it a couple of times
case 'SQLSTATE[HY000] [2002] Operation timed out':
echo 'Operation timed out (0-2002)';
die(4);
// special case "localhost" with a stopped db server (should not happen in docker compose setup)
case 'SQLSTATE[HY000] [2002] No such file or directory':
echo 'Connection could not be established (0-2002)';
die(5);
// using IP with stopped db server - the startup script should retry it a couple of times
case 'SQLSTATE[HY000] [2002] Connection refused':
echo 'Connection refused (0-2002)';
die(5);
}
echo $ex->getMessage() . " (0)";
die(7);
default:
// unknown error
echo $ex->getMessage() . " (?)";
die(10);
}
}

103
.docker/entrypoint.sh Executable file
View File

@@ -0,0 +1,103 @@
#!/bin/bash -x
KIMAI=$(cat /opt/kimai/version.txt)
echo $KIMAI
function waitForDB() {
# Parse sql connection data
DATABASE_USER=$(awk -F '[/:@]' '{print $4}' <<< "$DATABASE_URL")
DATABASE_PASS=$(awk -F '[/:@]' '{print $5}' <<< "$DATABASE_URL")
DATABASE_HOST=$(awk -F '[/:@]' '{print $6}' <<< "$DATABASE_URL")
DATABASE_PORT=$(awk -F '[/:@]' '{print $7}' <<< "$DATABASE_URL")
DATABASE_BASE=$(awk -F '[/?]' '{print $4}' <<< "$DATABASE_URL")
re='^[0-9]+$'
if ! [[ $DATABASE_PORT =~ $re ]] ; then
DATABASE_PORT=3306
fi
echo "Wait for database connection ..."
until php /dbtest.php "$DATABASE_HOST" "$DATABASE_BASE" "$DATABASE_PORT" "$DATABASE_USER" "$DATABASE_PASS"; do
echo Checking DB: $?
sleep 3
done
echo "Connection established"
}
function handleStartup() {
# set mem limits and copy in custom logger config
if [ -z "$memory_limit" ]; then
memory_limit=512M
fi
sed -i "s/memory_limit.*/memory_limit=$memory_limit/g" /usr/local/etc/php/php.ini
cp /assets/monolog.yaml /opt/kimai/config/packages/monolog.yaml
if [ -z "$USER_ID" ]; then
USER_ID=$(id -u www-data)
fi
if [ -z "$GROUP_ID" ]; then
GROUP_ID=$(id -g www-data)
fi
# if group doesn't exist
if grep -w "$GROUP_ID" /etc/group &>/dev/null; then
echo Group already exists
else
echo www-kimai:x:"$GROUP_ID": >> /etc/group
grpconv
fi
# if user doesn't exist
if id "$USER_ID" &>/dev/null; then
echo User already exists
else
echo www-kimai:x:"$USER_ID":"$GROUP_ID":www-kimai:/var/www:/usr/sbin/nologin >> /etc/passwd
pwconv
fi
if [ -e /use_apache ]; then
export APACHE_RUN_USER=$(id -nu "$USER_ID")
# This doesn't _exactly_ run as the specified GID, it runs as the GID of the specified user but WTF
export APACHE_RUN_GROUP=$(id -ng "$USER_ID")
export APACHE_PID_FILE=/var/run/apache2/apache2.pid
export APACHE_RUN_DIR=/var/run/apache2
export APACHE_LOCK_DIR=/var/lock/apache2
export APACHE_LOG_DIR=/var/log/apache2
export LANG=C
elif [ -e /use_fpm ]; then
sed -i "s/user = .*/user = $USER_ID/g" /usr/local/etc/php-fpm.d/www.conf
sed -i "s/group = .*/group = $GROUP_ID/g" /usr/local/etc/php-fpm.d/www.conf
echo "Setting fpm to run as ${USER_ID}:${GROUP_ID}"
else
echo "Error, unknown server type"
fi
}
function prepareKimai() {
# These are idempotent, so we can run them on every start-up
/opt/kimai/bin/console -n kimai:install
/opt/kimai/bin/console -n kimai:update
if [ ! -z "$ADMINPASS" ] && [ ! -a "$ADMINMAIL" ]; then
/opt/kimai/bin/console kimai:user:create admin "$ADMINMAIL" ROLE_SUPER_ADMIN "$ADMINPASS"
fi
echo "$KIMAI" > /opt/kimai/var/installed
echo "Kimai is ready"
}
function runServer() {
# Just while I'm fixing things
/opt/kimai/bin/console kimai:reload --env="$APP_ENV"
chown -R $USER_ID:$GROUP_ID /opt/kimai/var
if [ -e /use_apache ]; then
exec /usr/sbin/apache2 -D FOREGROUND
elif [ -e /use_fpm ]; then
exec php-fpm
else
echo "Error, unknown server type"
fi
}
waitForDB
handleStartup
prepareKimai
runServer

48
.docker/monolog.yaml Normal file
View File

@@ -0,0 +1,48 @@
when@prod:
monolog:
channels: ["deprecation"]
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [403, 404]
nested:
type: stream
level: info
path: php://stderr
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
channels: ["deprecation"]
path: php://stderr
when@dev:
monolog:
channels: ["deprecation"]
handlers:
main:
type: stream
path: php://stderr
level: info
channels: ["!event"]
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
deprecation:
type: stream
channels: ["deprecation"]
path: php://stderr
when@test:
monolog:
handlers:
main:
type: stream
path: php://stderr
level: info
channels: ["!event"]

View File

@@ -7,19 +7,19 @@
# Configure your database connection and set the correct server version.
#
# You have to replace the following values with your defaults:
# - the version "5.7"
# - the version "5.7" (the database server version, examples for MySQL and MariaDB below)
# - the database username "user"
# - the database password "password"
# - the database schema name "database"
# - the password "password" for "user"
# - the database schema "database"
# - you might have to adapt port "3306" and server IP "127.0.0.1" as well
#
# For MySQL that would be "serverVersion=5.7" as in:
# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8&serverVersion=5.7
# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=5.7
#
# For MariaDB it would be "serverVersion=mariadb-10.5.8":
# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8&serverVersion=mariadb-10.5.8
# For MariaDB it would be "serverVersion=10.5.8-MariaDB":
# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB
#
DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8&serverVersion=5.7
DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB
#================================================================================
# The full documentation can be found at https://www.kimai.org/documentation/emails.html

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,2 @@
github: [kevinpapst]
custom: ["https://www.kimai.org/donate/", "https://www.paypal.me/kevinpapst"]
custom: ["https://www.kimai.org/", "https://www.kimai.cloud/", "https://www.kevinpapst.de/"]

View File

@@ -3,12 +3,9 @@ contact_links:
- name: Read our documentation
url: https://www.kimai.org/documentation/
about: Save your time! There is an instant solution for many issues in the documentation.
- name: Docker image issue tracker
url: https://github.com/tobybatch/kimai2/issues
about: For issues specific for Kimai Docker deployment
- name: Ask a Question
url: https://github.com/kimai/kimai/discussions
about: Want to discuss something with a community? Do it in discussions!
- name: Get Professional support
url: https://www.kimai.org/store/custom-plugins.html
about: As a customer, you will always receive fast and helpful replies from the developer.
url: https://www.kimai.org/en/support.html
about: As a customer, you will always receive fast replies from the developer.

40
.github/ISSUE_TEMPLATE/docker.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Docker issue
description: Experiencing an issue with your Docker Setup?
labels: [ "docker" ]
body:
- type: markdown
attributes:
value: |
Thank you for reporting an issue with your docker setup! This form will guide you to create a useful issue report.
- type: textarea
id: describe
attributes:
label: Describe the problem
description: >
Please provide a clear and concise description of what the issue is and the steps to reproduce the behaviour:
1. Start the container '...'
2. Click on '....'
3. See error xyz
validations:
required: true
- type: textarea
id: environment
attributes:
label: Describe your setup and add your Docker compose file (redact your credentials)
description: >
Your working environment:
- OS: [e.g. Linux, Windows, Mac]
- Docker version: [e.g. 19.03.2]
- Docker compose version: [e.g. 1.21.0]
Docker compose file:
version: '3.5'
services:
image: ...
validations:
required: true
- type: input
id: command
attributes:
label: Command used to run the container
description: e.g. docker run -v ....

View File

@@ -1,17 +1,5 @@
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'
categories:
- title: 'Enhancements'
labels:
- 'feature request'
- 'technical debt'
- 'translation'
- title: 'Fixed bugs'
labels:
- 'bug'
- title: 'Infrastructure'
labels:
- 'infrastructure'
exclude-labels:
- 'duplicate'
- 'invalid'
@@ -33,10 +21,8 @@ version-resolver:
- 'translation'
default: patch
template: |
[Upgrade Kimai](https://www.kimai.org/documentation/updates.html) - [Install Kimai](https://www.kimai.org/documentation/installation.html) - [Docker](https://tobybatch.github.io/kimai2/)
**Compatible with PHP 8.1 and 8.2**
**Compatible with PHP 8.1 to 8.3**
$CHANGES
Involved in this release: $CONTRIBUTORS - thank you!
Involved in this release: $CONTRIBUTORS - thank you!

View File

@@ -1,16 +1,93 @@
name: 'Docker Build'
on:
release:
types: [released]
workflow_dispatch:
inputs:
kimai_tag:
description: 'Kimai tag to build'
required: true
release:
types: [released]
jobs:
build:
name: Trigger docker image build
runs-on: ubuntu-latest
steps:
- name: Emit repository_dispatch
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.DOCKER_ACCESS_TOKEN }}
repository: tobybatch/kimai2
event_type: kimai_release
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install buildx
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{secrets.DOCKERHUB_USERNAME}}
password: ${{secrets.DOCKERHUB_PASSWORD}}
- name: Determine version
run: |
input="${{ github.event.inputs.kimai_tag }}"
# Determine between manual trigger and release event
if [ -z "$input" ]; then
echo "Using release tag: ${{ github.event.release.tag_name }}"
version="${{ github.event.release.tag_name }}"
else
echo "Using tag provided: $input"
version="$input"
fi
if [[ ! $version =~ ^2\.(0|[1-9]*)(0?)\.(0|[0-9]*)(0?)$ ]]; then
echo "Invalid version number: $version"
exit 1
fi
echo "kimai_version=$version" >> $GITHUB_ENV
- name: FPM image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
build-args: |
KIMAI=${{ env.kimai_version }}
BASE=fpm
target: prod
platforms: linux/amd64,linux/arm64
tags: |
kimai/kimai2:latest
kimai/kimai2:fpm
kimai/kimai2:fpm-${{ env.kimai_version }}
push: true
- name: Apache image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
build-args: |
KIMAI=${{ env.kimai_version }}
BASE=apache
target: prod
platforms: linux/amd64,linux/arm64
tags: |
kimai/kimai2:apache
kimai/kimai2:apache-${{ env.kimai_version }}
push: true
- name: Development image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
build-args: |
KIMAI=${{ env.kimai_version }}
BASE=apache
target: dev
platforms: linux/amd64,linux/arm64
tags: |
kimai/kimai2:dev
push: true

29
.github/workflows/lock-threads.yaml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: 'Lock Threads'
on:
schedule:
- cron: '17 1 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock-threads
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
with:
process-only: 'issues, prs'
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '90'
issue-comment: >
This thread has been automatically locked since there has not been any recent activity after it was closed.
Please share your experience with the community and [leave a testimonial](https://love.kimai.org/) to support Kimai.
issue-lock-reason: 'resolved'
pr-inactive-days: '180'
log-output: true

View File

@@ -1,56 +0,0 @@
name: 'Lock Threads'
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
with:
github-token: ${{ github.token }}
issue-inactive-days: '90'
exclude-issue-created-before: ''
exclude-issue-created-after: ''
exclude-issue-created-between: ''
exclude-issue-closed-before: ''
exclude-issue-closed-after: ''
exclude-issue-closed-between: ''
include-any-issue-labels: ''
include-all-issue-labels: ''
exclude-any-issue-labels: ''
add-issue-labels: ''
remove-issue-labels: ''
issue-comment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
If you use Kimai on a daily basis, please [consider donating](https://www.kimai.org/donate/) to
support further development of Kimai.
issue-lock-reason: 'resolved'
pr-inactive-days: '180'
exclude-pr-created-before: ''
exclude-pr-created-after: ''
exclude-pr-created-between: ''
exclude-pr-closed-before: ''
exclude-pr-closed-after: ''
exclude-pr-closed-between: ''
include-any-pr-labels: ''
include-all-pr-labels: ''
exclude-any-pr-labels: ''
add-pr-labels: ''
remove-pr-labels: ''
pr-comment: ''
pr-lock-reason: ''
process-only: ''
log-output: false

View File

@@ -11,7 +11,7 @@ jobs:
steps:
- name: Clone Kimai
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
persist-credentials: false
@@ -19,5 +19,5 @@ jobs:
uses: xalvarez/prevent-file-change-action@v1
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
pattern: .*.lock
pattern: .*\.lock$
trustedAuthors: kevinpapst, dependabot

View File

@@ -25,6 +25,6 @@ jobs:
needs: correct_repository
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
- uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,13 +19,13 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
matrix:
php: ['8.1', '8.2']
php: ['8.1', '8.2', '8.3']
name: Integration (${{ matrix.php }})
steps:
- name: Clone Kimai
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
persist-credentials: false
@@ -39,12 +39,15 @@ jobs:
env:
fail-fast: true
- name: Determine software versions
run: mysql --version && php --version
- name: Determine composer cache directory
id: composer-cache
run: echo "composer_cache_directory=$(composer config cache-dir)" >> $GITHUB_ENV
- name: Cache Composer dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: "${{ env.composer_cache_directory }}"
key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
@@ -53,7 +56,7 @@ jobs:
run: composer install
- name: Validate Composer
run: composer validate --strict
run: composer validate --strict --no-check-all
- name: Warmup cache
run: APP_ENV=dev bin/console kimai:reload -n
@@ -79,21 +82,29 @@ jobs:
- name: Run quick unit-tests
run: composer tests-unit
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
APP_ENV: dev
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
APP_ENV: test
MAILER_URL: null://localhost
- name: Full test-suite
if: matrix.php != '8.2'
run: vendor/bin/phpunit tests/
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
APP_ENV: test
MAILER_URL: null://localhost
- name: Full test-suite with coverage
if: matrix.php == '8.2'
run: vendor/bin/phpunit tests/ --coverage-clover=coverage.xml
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
APP_ENV: dev
MAILER_URL: null://localhost
TEST_WITH_BUNDLES: 1
- name: Upload code coverage
if: matrix.php == '8.1'
uses: codecov/codecov-action@v3
if: matrix.php == '8.2'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
@@ -106,7 +117,7 @@ jobs:
bin/console doctrine:migrations:migrate -n
bin/console doctrine:migrations:migrate first -n
env:
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?serverVersion=5.7
DATABASE_URL: mysql://root:kimai@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/kimai?charset=utf8mb4&serverVersion=8.0.35
APP_ENV: dev
MAILER_URL: null://localhost

42
.github/workflows/website.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: 'Website update'
on:
workflow_dispatch:
inputs:
kimai_version:
description: 'Kimai version for the website'
required: true
release:
types: [released]
jobs:
build:
name: Trigger version update for website
runs-on: ubuntu-latest
steps:
- name: "Determine Version"
run: |
input="${{ github.event.inputs.kimai_version }}"
# Determine between manual trigger and release event
if [ -z "$input" ]; then
echo "No input provided, using release tag"
version="${{ github.event.release.tag_name }}"
else
echo "Using input provided: $input"
version="$input"
fi
echo "kimai_version=$version" >> $GITHUB_ENV
if [[ ! $version =~ ^2\.(0|[1-9]*)(0?)\.(0|[0-9]*)(0?)$ ]]; then
echo "Invalid version number: $version"
exit 1
fi
- name: Emit repository_dispatch
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.WEBSITE_ACCESS_TOKEN }}
repository: kimai/www.kimai.org
event-type: kimai_release
client-payload: '{"kimai_version": "${{ env.kimai_version }}"}'

43
.gitignore vendored
View File

@@ -1,41 +1,32 @@
# some hosters require a htaccess to change the PHP version
.htaccess
.env-*
.idea/
/public/.htaccess
/.env-*
/.idea/
.DS_Store
rector.php
phpstan.sh
# custom apache rules e.g. to deactivate ioncube loader
/public/.user.ini
# for symfony local webserver
php.ini
.php-version
/php.ini
/.php-version
# YARN 2
.yarnrc.yml
.yarn
/.yarnrc.yml
/.yarn
# for keeping empty directories
!.gitkeep
/bin/*
!/bin/console
*local.yaml
/config/packages/local.yaml
/config/bundles-local.php
/templates/invoice/renderer/.~lock*
/translations/branding.*.xlf
/var/data/*
/var/coverage/
/var/cache/*
/var/invoices/*
/var/export/*
/var/invoices*
/var/export*
/var/log/*
/var/sessions/*
/var/packages/*
/var/plugins/*
*.disabled
/var/plugins*
/var/plugins/*/*.disabled
###> symfony/framework-bundle ###
/.env.local
@@ -67,4 +58,6 @@ php.ini
npm-debug.log
yarn-error.log
###< symfony/webpack-encore-bundle ###
/nbproject/*
/nbproject/*
.dockerhub.secrets

View File

@@ -9,12 +9,17 @@ COMMENT;
$fixer = new PhpCsFixer\Config();
$fixer
->setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect())
->setRiskyAllowed(true)
->setRules([
'encoding' => true,
'full_opening_tag' => true,
'blank_line_after_namespace' => true,
'braces' => true,
'control_structure_braces' => true,
'control_structure_continuation_position' => ['position' => 'same_line'],
'declare_parentheses' => true,
'no_multiple_statements_per_line' => true,
'statement_indentation' => true,
'class_definition' => true,
'elseif' => true,
'function_declaration' => true,
@@ -29,7 +34,7 @@ $fixer
'no_break_comment' => true,
'no_closing_tag' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'spaces_inside_parentheses' => ['space' => 'none'],
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'single_blank_line_at_eof' => true,
@@ -50,13 +55,13 @@ $fixer
'class_attributes_separation' => ['elements' => ['method' => 'one']],
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'type_declaration_spaces' => ['elements' => ['function', 'property']],
'include' => true,
'lowercase_cast' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'native_function_casing' => true,
'new_with_braces' => true,
'new_with_parentheses' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
@@ -78,7 +83,7 @@ $fixer
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_around_offset' => true,
'no_trailing_comma_in_singleline' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_braces' => true,
'no_unneeded_final_method' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
@@ -119,7 +124,7 @@ $fixer
'return_type_declaration' => true,
'semicolon_after_instruction' => true,
'short_scalar_cast' => true,
'single_blank_line_before_namespace' => true,
'blank_lines_before_namespace' => ['min_line_breaks' => 2, 'max_line_breaks' => 2],
'single_line_comment_style' => [
'comment_types' => ['hash'],
],
@@ -147,7 +152,7 @@ $fixer
],
'scope' => 'namespaced'
],
'native_function_type_declaration_casing' => true,
'native_type_declaration_casing' => true,
'no_alias_functions' => [
'sets' => [
'@internal'
@@ -166,6 +171,7 @@ $fixer
->setFinder(
PhpCsFixer\Finder::create()
->in([
__DIR__ . '/migrations/',
__DIR__ . '/src/',
__DIR__ . '/tests/',
])

333
Dockerfile Normal file
View File

@@ -0,0 +1,333 @@
# _ ___ _
# | |/ (_)_ __ ___ __ _(_)
# | ' /| | '_ ` _ \ / _` | |
# | . \| | | | | | | (_| | |
# |_|\_\_|_| |_| |_|\__,_|_|
#
# Kimai images for:
# - plain PHP FPM (kimai/kimai2:fpm)
# - Apache with PHP (kimai/kimai2:apache)
# - Development (kimai/kimai2:dev)
# ---------------------------------------------------------------------
# For local testing by maintainer:
#
# docker build --no-cache -t kimai-fpm --build-arg BASE=fpm .
# docker build --no-cache -t kimai-apache --build-arg BASE=apache .
# docker run -d --name kimai-apache-app kimai-apache
# docker exec -ti kimai-apache-app /bin/bash
# ---------------------------------------------------------------------
# Official PHP images: https://hub.docker.com/_/php/
# https://github.com/docker-library/docs/blob/master/php/README.md#supported-tags-and-respective-dockerfile-links
# Pass-through Arguments: https://benkyriakou.com/posts/docker-args-empty
# Best practices: https://docs.docker.com/build/building/best-practices/
# ---------------------------------------------------------------------
# Source base, one of: fpm, apache
ARG BASE="fpm"
# Kimai branch/tag to run
ARG KIMAI="main"
# Timezone for images
ARG TIMEZONE="Europe/Berlin"
###########################
# Shared tools
###########################
# composer base image
FROM composer:latest AS composer
###########################
# PHP extensions
###########################
# fpm alpine php extension base
FROM php:8.3-fpm-alpine AS fpm-php-ext-base
RUN apk add --no-cache \
# build-tools
autoconf \
dpkg \
dpkg-dev \
file \
g++ \
gcc \
icu-dev \
libatomic \
libc-dev \
libgomp \
libmagic \
m4 \
make \
mpc1 \
mpfr4 \
musl-dev \
perl \
re2c \
# gd
freetype-dev \
libpng-dev \
# icu
icu-dev \
icu-data-full \
# ldap
openldap-dev \
libldap \
# zip
libzip-dev \
# xsl
libxslt-dev
# apache debian php extension base
FROM php:8.3-apache-bookworm AS apache-php-ext-base
RUN apt-get update && \
apt-get install -y \
libldap2-dev \
libicu-dev \
libpng-dev \
libzip-dev \
libxslt1-dev \
libfreetype6-dev
# php extension gd - 13.86s
FROM ${BASE}-php-ext-base AS php-ext-gd
RUN docker-php-ext-configure gd \
--with-freetype && \
docker-php-ext-install -j$(nproc) gd
# php extension intl : 15.26s
FROM ${BASE}-php-ext-base AS php-ext-intl
RUN docker-php-ext-install -j$(nproc) intl
# php extension ldap : 8.45s
FROM ${BASE}-php-ext-base AS php-ext-ldap
RUN docker-php-ext-configure ldap && \
docker-php-ext-install -j$(nproc) ldap
# php extension pdo_mysql : 6.14s
FROM ${BASE}-php-ext-base AS php-ext-pdo_mysql
RUN docker-php-ext-install -j$(nproc) pdo_mysql
# php extension zip : 8.18s
FROM ${BASE}-php-ext-base AS php-ext-zip
RUN docker-php-ext-install -j$(nproc) zip
# php extension xsl : ?.?? s
FROM ${BASE}-php-ext-base AS php-ext-xsl
RUN docker-php-ext-install -j$(nproc) xsl
# php extension opcache
FROM ${BASE}-php-ext-base AS php-ext-opcache
RUN docker-php-ext-install -j$(nproc) opcache
###########################
# fpm base build
###########################
FROM php:8.3-fpm-alpine AS fpm-base
ARG TIMEZONE
RUN apk add --no-cache \
bash \
coreutils \
freetype \
haveged \
icu \
icu-data-full \
libldap \
libpng \
libzip \
libxslt-dev \
fcgi \
tzdata && \
touch /use_fpm && \
sed -i "s/;ping.path/ping.path/g" /usr/local/etc/php-fpm.d/www.conf && \
sed -i "s/;access.suppress_path\[\] = \/ping/access.suppress_path\[\] = \/ping/g" /usr/local/etc/php-fpm.d/www.conf
EXPOSE 9000
HEALTHCHECK --interval=20s --timeout=10s --retries=3 \
CMD \
SCRIPT_NAME=/ping \
SCRIPT_FILENAME=/ping \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 1
###########################
# apache base build
###########################
FROM php:8.3-apache-bookworm AS apache-base
ARG TIMEZONE
RUN apt-get update && \
apt-get install -y \
bash \
haveged \
libicu72 \
libldap-common \
libpng16-16 \
libzip4 \
libxslt1.1 \
libfreetype6 \
unzip && \
echo "Listen 8001" > /etc/apache2/ports.conf && \
a2enmod rewrite && \
touch /use_apache
COPY .docker/000-default.conf /etc/apache2/sites-available/000-default.conf
EXPOSE 8001
HEALTHCHECK --interval=20s --timeout=10s --retries=3 \
CMD curl -f http://127.0.0.1:8001 || exit 1
###########################
# global base build
###########################
FROM ${BASE}-base AS php-base
ARG TIMEZONE
ENV TIMEZONE=${TIMEZONE}
RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && echo ${TIMEZONE} > /etc/timezone && \
# make composer home dir
mkdir /composer && \
chown -R www-data:www-data /composer
# copy composer
COPY --from=composer /usr/bin/composer /usr/bin/composer
# copy php extensions
# PHP extension xsl
COPY --from=php-ext-xsl /usr/local/etc/php/conf.d/docker-php-ext-xsl.ini /usr/local/etc/php/conf.d/docker-php-ext-xsl.ini
COPY --from=php-ext-xsl /usr/local/lib/php/extensions/no-debug-non-zts-20230831/xsl.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/xsl.so
# PHP extension pdo_mysql
COPY --from=php-ext-pdo_mysql /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini /usr/local/etc/php/conf.d/docker-php-ext-pdo_mysql.ini
COPY --from=php-ext-pdo_mysql /usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so
# PHP extension zip
COPY --from=php-ext-zip /usr/local/etc/php/conf.d/docker-php-ext-zip.ini /usr/local/etc/php/conf.d/docker-php-ext-zip.ini
COPY --from=php-ext-zip /usr/local/lib/php/extensions/no-debug-non-zts-20230831/zip.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/zip.so
# PHP extension ldap
COPY --from=php-ext-ldap /usr/local/etc/php/conf.d/docker-php-ext-ldap.ini /usr/local/etc/php/conf.d/docker-php-ext-ldap.ini
COPY --from=php-ext-ldap /usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so
# PHP extension gd
COPY --from=php-ext-gd /usr/local/etc/php/conf.d/docker-php-ext-gd.ini /usr/local/etc/php/conf.d/docker-php-ext-gd.ini
COPY --from=php-ext-gd /usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so
# PHP extension intl
COPY --from=php-ext-intl /usr/local/etc/php/conf.d/docker-php-ext-intl.ini /usr/local/etc/php/conf.d/docker-php-ext-intl.ini
COPY --from=php-ext-intl /usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so /usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so
# PHP extension opcache
COPY --from=php-ext-opcache /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
###########################
# Shared tools
###########################
# full kimai source
FROM alpine:latest AS git-dev
ARG KIMAI
ARG TIMEZONE
RUN apk add --no-cache git && \
git clone --depth 1 --branch ${KIMAI} https://github.com/kimai/kimai.git /opt/kimai
# production kimai source
FROM git-dev AS git-prod
WORKDIR /opt/kimai
RUN rm -r tests
###########################
# global base build
###########################
FROM php-base AS base
ARG KIMAI
ARG TIMEZONE
LABEL org.opencontainers.image.title="Kimai" \
org.opencontainers.image.description="Kimai is a time-tracking application." \
org.opencontainers.image.authors="Kimai Community" \
org.opencontainers.image.url="https://www.kimai.org/" \
org.opencontainers.image.documentation="https://www.kimai.org/documentation/" \
org.opencontainers.image.source="https://github.com/kimai/kimai" \
org.opencontainers.image.version="${KIMAI}" \
org.opencontainers.image.vendor="Kevin Papst" \
org.opencontainers.image.licenses="AGPL-3.0"
ENV KIMAI=${KIMAI}
ENV TIMEZONE=${TIMEZONE}
RUN ln -snf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && echo ${TIMEZONE} > /etc/timezone && \
mkdir -p /composer && \
chown -R www-data:www-data /composer
# copy startup script & DB checking script
COPY .docker/dbtest.php /dbtest.php
COPY .docker/entrypoint.sh /entrypoint.sh
ENV DATABASE_URL="mysql://kimai:kimai@127.0.0.1:3306/kimai?charset=utf8mb4&serverVersion=8.3"
ENV APP_SECRET=change_this_to_something_unique
# The default container name for nginx is nginx
ENV TRUSTED_PROXIES=nginx,localhost,127.0.0.1
ENV MAILER_FROM=kimai@example.com
ENV MAILER_URL=null://localhost
ENV ADMINPASS=
ENV ADMINMAIL=
ENV USER_ID=
ENV GROUP_ID=
# default values to configure composer behavior
ENV COMPOSER_MEMORY_LIMIT=-1
ENV COMPOSER_ALLOW_SUPERUSER=1
VOLUME [ "/opt/kimai/var" ]
CMD [ "/entrypoint.sh" ]
###########################
# final builds
###########################
# development build
FROM base AS dev
# copy kimai develop source
COPY --from=git-dev --chown=www-data:www-data /opt/kimai /opt/kimai
COPY .docker /assets
# do the composer deps installation
RUN echo \$PATH
RUN \
export COMPOSER_HOME=/composer && \
composer --no-ansi install --working-dir=/opt/kimai --optimize-autoloader && \
composer --no-ansi clearcache && \
composer --no-ansi require --working-dir=/opt/kimai laminas/laminas-ldap && \
cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini && \
chown -R www-data:www-data /opt/kimai /usr/local/etc/php/php.ini && \
mkdir -p /opt/kimai/var/logs && chmod 777 /opt/kimai/var/logs && \
sed "s/128M/-1/g" /usr/local/etc/php/php.ini-development > /opt/kimai/php-cli.ini && \
sed -i "s/env php/env -S php -c \/opt\/kimai\/php-cli.ini/g" /opt/kimai/bin/console && \
/opt/kimai/bin/console kimai:version | awk '{print $2}' > /opt/kimai/version.txt
ENV APP_ENV=dev
ENV DATABASE_URL=
ENV memory_limit=512M
# production build
FROM base AS prod
# copy kimai production source
COPY --from=git-prod --chown=www-data:www-data /opt/kimai /opt/kimai
COPY .docker /assets
# do the composer deps installation
RUN \
export COMPOSER_HOME=/composer && \
composer --no-ansi install --working-dir=/opt/kimai --no-dev --optimize-autoloader && \
composer --no-ansi clearcache && \
composer --no-ansi require --update-no-dev --working-dir=/opt/kimai laminas/laminas-ldap && \
cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini && \
sed -i "s/expose_php = On/expose_php = Off/g" /usr/local/etc/php/php.ini && \
sed -i "s/;opcache.enable=1/opcache.enable=1/g" /usr/local/etc/php/php.ini && \
sed -i "s/;opcache.memory_consumption=128/opcache.memory_consumption=256/g" /usr/local/etc/php/php.ini && \
sed -i "s/;opcache.interned_strings_buffer=8/opcache.interned_strings_buffer=24/g" /usr/local/etc/php/php.ini && \
sed -i "s/;opcache.max_accelerated_files=10000/opcache.max_accelerated_files=100000/g" /usr/local/etc/php/php.ini && \
sed -i "s/opcache.validate_timestamps=1/opcache.validate_timestamps=0/g" /usr/local/etc/php/php.ini && \
sed -i "s/session.gc_maxlifetime = 1440/session.gc_maxlifetime = 604800/g" /usr/local/etc/php/php.ini && \
mkdir -p /opt/kimai/var/logs && chmod 777 /opt/kimai/var/logs && \
sed "s/128M/-1/g" /usr/local/etc/php/php.ini-development > /opt/kimai/php-cli.ini && \
chown -R www-data:www-data /opt/kimai /usr/local/etc/php/php.ini && \
/opt/kimai/bin/console kimai:version | awk '{print $2}' > /opt/kimai/version.txt
ENV APP_ENV=prod
ENV DATABASE_URL=
ENV memory_limit=512M

View File

@@ -3,7 +3,7 @@
</p>
<p align="center">
<a href="https://github.com/kimai/kimai/actions"><img alt="CI Status" src="https://github.com/kimai/kimai/workflows/CI/badge.svg"></a>
<a href="https://github.com/kimai/kimai/actions"><img alt="CI Status" src="https://github.com/kimai/kimai/actions/workflows/testing.yaml/badge.svg"></a>
<a href="https://codecov.io/gh/kimai/kimai"><img alt="Code Coverage" src="https://codecov.io/gh/kimai/kimai/branch/main/graph/badge.svg"></a>
<a href="https://packagist.org/packages/kimai/kimai"><img alt="Latest stable version" src="https://poser.pugx.org/kimai/kimai/v/stable"></a>
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html"><img alt="License" src="https://poser.pugx.org/kimai/kimai/license"></a>
@@ -23,10 +23,10 @@ and so much more.
### Versions
There are two versions of Kimai existing:
There are two [versions](https://www.kimai.org/documentation/versions.html) of Kimai existing:
- [Version 1](https://github.com/kimai/kimai/tree/1.x) — compatible with PHP 7.4, which is in maintenance mode since 2023
- [Version 2](https://github.com/kimai/kimai) — stable and "almost released" (waiting for some major plugins, which are not yet migrated)
- [Version 2](https://github.com/kimai/kimai) — the current stable release (PHP 8.1+)
- [Version 1](https://github.com/kimai/kimai/tree/1.x) — do **NOT** use, EOL since mid of 2023 (PHP 7.4)
### Links
@@ -36,21 +36,20 @@ There are two versions of Kimai existing:
### Requirements
- PHP 8.1 minimum
- PHP 8.1.3 minimum (support for PHP 8.2 and 8.3)
- MariaDB or MySQL
- A webserver and subdomain (subdirectory is not supported)
- PHP extensions: `gd`, `intl`, `json`, `mbstring`, `pdo`, `tokenizer`, `xml`, `xsl`, `zip`
## Installation
- [Recommended setup](https://www.kimai.org/documentation/installation.html#recommended-setup) — with Git and Composer
- [Docker](https://hub.docker.com/r/kimai/kimai2) — containerized by [@tobybatch](https://github.com/tobybatch/kimai2)
- Caddy with Docker-Compose at [Hetzner](https://www.kimai.org/documentation/hosting-hetzner-cloud.html) and [DigitalOcean](https://www.kimai.org/documentation/hosting-digital-ocean.html)
- [SSH setup](https://www.kimai.org/documentation/installation.html) with Git and Composer
- [Docker images](https://hub.docker.com/r/kimai/kimai2) with FPM only or incl. Apache
- [Synology](https://www.kimai.org/documentation/synology.html) user can host the Docker version
- [Developer setups](https://www.kimai.org/documentation/developers.html) if you want to create Kimai integrations
There are also documentations for:
- [developer setups](https://www.kimai.org/documentation/developers.html) — on your local machine
- [shared hostings](https://www.kimai.org/documentation/installation.html#shared-hosting) — the least favorable option
- [Synology](https://www.kimai.org/documentation/synology.html) — you could try to host the Docker version instead
- [1-click installer](https://www.kimai.org/documentation/installation.html#hosting-and-1-click-installations) — hosted environments
There are more documented ways for [on-premise hosting](https://www.kimai.org/documentation/chapter-on-premise.html).
And if you don't want to host Kimai, you can use [the Cloud version](https://www.kimai.cloud/) of it.
@@ -61,19 +60,16 @@ And if you don't want to host Kimai, you can use [the Cloud version](https://www
### Plugins
- [Plugin marketplace](https://www.kimai.org/store/) — find existing plugins here
- [Plugins](https://www.kimai.org/store/) — paid and free plugin marketplace
- [Developer documentation](https://www.kimai.org/documentation/developers.html) — how to create a plugin
## Roadmap and releases
You can see a rough development roadmap in the [Milestones](https://github.com/kimai/kimai/milestones) sections.
It is open for changes and input from the community, your [ideas and questions](https://github.com/kimai/kimai/issues) are welcome.
You can see a rough development [roadmap](https://github.com/orgs/kimai/projects/2), which is open for changes and input from the community, your [ideas](https://github.com/kimai/kimai/issues) are welcome.
Release versions will be created on a regular basis, every couple of weeks latest.
Every code change, whether it's a new feature or a bugfix, will be done on the `main` branch.
For the time being and until 2.0 is widely adopted, the [1.x branch](https://github.com/kimai/kimai/tree/1.x) will receive bug fixes.
## Contributing
You want to contribute to this repository? This is so great!
@@ -81,7 +77,7 @@ The best way to start is to [open a new issue](https://github.com/kimai/kimai/is
In case you want to contribute, but you wouldn't know how, here are some suggestions:
- Spread the word: More user means more people testing and contributing to Kimai, which in turn means better stability and more and better features. Please vote for Kimai on any software platform, you can toot or tweet about it, share it on LinkedIn, Reddit or any of your favorite social media platforms. Every bit helps!
- Spread the word: Please [write a testimonial for our Wall of love](https://love.kimai.org), vote for Kimai on any software platform, you can toot or tweet about it, share it on LinkedIn, Reddit and any other social media platform!
- Answer questions: You know the answer to another user's problem? Share your knowledge.
- Something can be done better? An essential feature is missing? Create a feature request.
- Report bugs makes Kimai better for everyone.

View File

@@ -1,24 +1,11 @@
# Security Policy
## Supported Versions
As announced in the [README](README.md) I only support the latest available release and `main` branch.
As announced in the [README](README.md) security fixes will only be added to the `main` branch.
| Version | Supported |
|----------------------|--------------------|
| main branch | :white_check_mark: |
| latest minor release | :white_check_mark: |
| older releases | :x: |
## Reporting a Vulnerability
Please read the [Bughunter](https://www.kimai.org/documentation/bughunter.html) documentation before posting.
You can report any security related vulnerability in the [advisory section at GitHub](https://github.com/kimai/kimai/security/advisories) or via email to kpapst@gmx.net.
I will work as fast as I can to fix the problem and publish a bugfix release / security update.
Depending on the size of the required fixes, this might take a couple of hours or a couple of days.
You can expect that your message will be answered ASAP.
You will be mentioned in the release notes if your issue is valid.
I am grateful for any (discrete) disclosure of vulnerabilities!
You find all information in our [Bughunter documentation](https://www.kimai.org/documentation/bughunter.html).

368
UPGRADING-1.md Normal file
View File

@@ -0,0 +1,368 @@
# Upgrading Kimai - Version 1.x
_Make sure to create a backup before you start!_
Read the [updates documentation](https://www.kimai.org/documentation/updates.html) to find out how
you can upgrade your Kimai installation to the latest stable release.
Check below if there are more version specific steps required, which need to be executed after the normal update process.
Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation.
## [1.16](https://github.com/kimai/kimai/releases/tag/1.16)
If you are using MariaDB, it must be at least version 10.1, older versions are not supported any longer.
**DEVELOPER**
- Removed `formDateTime` field from API model `I18nConfig`
- Upgraded to Doctrine DBAL 3, see [docs](https://github.com/doctrine/dbal/blob/3.1.x/UPGRADE.md) - you might have to update your bundle
## [1.15](https://github.com/kimai/kimai/releases/tag/1.15)
**Many database changes: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Updating the database might take quite a while, depending on the amount of timesheet entries and speed of your database server (~1 minute per 100k records).
**ATTENTION**
- This release bumps the minimum required [PHP version to 7.3](https://www.kimai.org/blog/2021/php8-support-php72-dropped/)
- Self-registration is disabled by default
- Self-registration now always requires email confirmation
- All plugins that use own databases need to be updated as well
- Removed the YearChart widget and the related configs named `userRecapThisYear`, `userRecapLastYear`, `userRecapTwoYears`, `userRecapThreeYears`
**LDAP & SAML**
Please verify your config with the [LDAP](https://www.kimai.org/documentation/ldap.html) and [SAML](https://www.kimai.org/documentation/saml.html) documentation, especially:
- SAML users: activate it by setting the `kimai.saml.activate: true` config key
- LDAP users: activate it by setting the `kimai.ldap.activate: true` config key
- LDAP and SAML users need to remove the complete `security` section from their `local.yaml`
**DEVELOPER**
PHP 8 compatibility forced to upgrade MANY libraries, including but not limited to:
- Removed FOSUserBundle and hslavich/oneloginsaml
- Doctrine Migrations, whose new major version forces plugin updates
- Gedmo v3 (which include BC breaks in definitions)
- Doctrine DBAL and others, which required PHP 7.3 as well
**API BC break**: Due to team structure changes, it was impossible to keep the (writing) API structure. Please adjust your code accordingly!
## [1.14](https://github.com/kimai/kimai/releases/tag/1.14)
**CRITICAL BC break**: SQLite support was removed. If you are using SQLite, you have to [read this blog post](https://www.kimai.org/blog/2021/sqlite-and-ftp-support-removed/) and migrate to MySQL/MariaDB first!
**New database tables and fields: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Permission changes:
- `history_invoice` - removed permission entirely
## [1.13](https://github.com/kimai/kimai/releases/tag/1.13)
- Deprecated `now` variable in export templates: create it yourself with `{% set now = create_date('now', app.user) %}`
- Changed invoice filename generation (check if you use cronjob for invoices)
- **BC break**: duration entered as plain numbers will now be treated as decimal duration in hours instead of seconds
## [1.12](https://github.com/kimai/kimai/releases/tag/1.12)
- Export templates can now include items from plugins (eg. Expenses).
## [1.10](https://github.com/kimai/kimai/releases/tag/1.10)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- Invoice renderer `CSV` was removed
- Sessions are now stored in the database (all users have to re-login after upgrade)
- New permissions: `lockdown_grace_timesheet`, `lockdown_override_timesheet`, `view_all_data`
- Fixed team permissions on user queries: depending on your previous team & permission setup your users might see less data (SUPER_ADMINS see all data, but new: ADMINS only see all data if they own the `view_all_data` permission)
- Markdown does not support headings anymore, text like `# foo` is not converted to `<h1 id="foo">foo</h1>` anymore
### Developer
- **BC break**: removed registration of `.env` with `putenv()` - do not rely on `getenv()` as it is not thread-safe
- **BC break**: interface method signature `HtmlToPdfConverter::convertToPdf()` changed
- **BC break**: the macros `badge` and `label` do not apply the `|trans` filter any more
- **BC Break**: removed `getVisible()` (deprecated since 1.4) method on Customer, Project and Activity (use `isVisible()` instead, templates are still working)
- **BC Break**: API changes
- some representation names changed (eg. from `ActivityMetaField` to `ActivityMeta`, `TimesheetSubCollection` vs `TimesheetCollectionExpanded`), you could use `class_alias()` if you use auto-generated code from Swagger-Gen or alike
- new result types were introduced
- result data changed in some areas to smooth out inconsistencies (eg. TeamEntity fields changed in nested results)
## [1.9](https://github.com/kimai/kimai/releases/tag/1.9)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- The directory `var/data/invoices/` will be used to store archived invoice files (check file permissions)
- The default invoice number format changed. If you want to use the old one: configure `{date}` as format - see [invoice documentation](https://www.kimai.org/documentation/invoices.html)
- HTML invoice templates are now treated like other files and offered as download. If you are using relative URLs for including assets (CSS, images) you need to either inline them (see the default templates) or use absolute URLs
- Invoice templates that use the templates variables `${activity.X}` or `${project.X}` should be checked and possibly adapted, as multi-select is now possible for filtering
- Invoice templates have access to all meta-fields as variables, not only the ones marked as visible
- Rates configuration/structure changed for customer, project and activity
- **Invoice templates**: rates variables were removed
Permission changes:
- `history_invoice` - NEW: grants all features for the new invoice archive (by default for all admins)
### Developer
- **BC break**: `InvoiceItemInterface` has new methods `getType()` and `getCategory()`
- **BC break**: API fields changed - see new `/rates` endpoints
## [1.8](https://github.com/kimai/kimai/releases/tag/1.8)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- New PHP requirement: `ext-xsl` - which should be pre-installed in most environments when `ext-xml` is loaded
- New mailer library: check if emails are still working (eg. by using the "password forgotten" function) or if you need to adjust your configuration, [see docs at symfony.com](https://symfony.com/doc/current/components/mailer.html#transport)
- Support for line breaks in multiline invoice fields for spreadsheets (check your invoice templates after the update)
Permission changes:
- `comments_create_customer` - NEW: permission that allows to add new comments for customers
- `comments_create_team_customer` - NEW: permission that allows to add new comments for team members of the current customer
- `comments_create_teamlead_customer` - NEW: permission that allows to add new comments for a teamlead of the current customer
- `comments_create_project` - NEW: permission that allows to add new comments for project
- `comments_create_team_project` - NEW: permission that allows to add new comments for team members of the current project
- `comments_create_teamlead_project` - NEW: permission that allows to add new comments for a teamlead of the current project
- `edit_teamlead_project` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `edit_teamlead_customer` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `upload_invoice_template` - NEW: permission that allows to upload invoice documents from the UI
## [1.7](https://github.com/kimai/kimai/releases/tag/1.7)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
New permissions:
- `comments_customer` - show comment list on customer detail page (new feature)
- `details_customer` - show detail information for customers (customer number, vat, rates, meta-fields, assigned teams ...)
- `comments_project` - show comment list on project detail page (new feature)
- `details_project` - show detail information for projects (rates, meta-fields, assigned teams ...)
If you are using teams, please read on: The following list of permissions are now also available in the UI and they (can) replace the `X_project` and `X_customer` permissions.
They are more strict, as they allow only access to team specific items, the older permissions without `_teamlead_`/`_team_` work on a global level instead.
- `view_teamlead_customer`, `edit_teamlead_customer`, `budget_teamlead_customer`, `permissions_teamlead_customer`, `comments_teamlead_customer`, `details_teamlead_customer` - allows access to customer data when user is teamlead of a team assigned to the customer (replaces more global permission like `view_customer` for teamleads)
- `view_team_customer`, `edit_team_customer`, `budget_team_customer`, `comments_team_customer`, `details_team_customer` - allows access to customer data when user is member of a team assigned to the customer (replaces more global permission like `view_customer` for users)
- `view_teamlead_project`, `edit_teamlead_project`, `budget_teamlead_project`, `permissions_teamlead_project`, `comments_teamlead_project`, `details_teamlead_project` - allows access to customer data when user is teamlead of a team assigned to the project (replaces more global permission like `view_project` for teamleads)
- `view_team_project`, `edit_team_project`, `budget_team_project`, `comments_team_project`, `details_team_project` - allows access to customer data when user is member of a team assigned to the project (replaces more global permission like `view_project` for users)
### ExpenseBundle
**ATTENTION** due to incompatibilities in the underlying frameworks users of the ExpenseBundle need to do one more step:
You need to delete the bundle before updating: `rm -r var/plugins/ExpenseBundle`, otherwise you will run into errors during the update.
After the Kimai update was successful, you have to re-install the latest bundle version, which is compatible with Kimai 1.7 only.
### Developer
- Projects now have a start and end date and the API will only return those, which are either unconfigured or currently active, you might want to reload the list of projects once the user entered begin and end datetime OR use the new `ignoreDates` parameter.
- Doctrine bundle was updated to v2, check your code for [the usage of RegistryInterface and ObjectManager](https://github.com/doctrine/DoctrineBundle/blob/master/UPGRADE-2.0.md)
- Removed the webserver bundle and the command `server:run` - see [docs](https://www.kimai.org/documentation/developers.html)
## [1.6](https://github.com/kimai/kimai/releases/tag/1.6), [1.6.1](https://github.com/kimai/kimai/releases/tag/1.6.1), [1.6.2](https://github.com/kimai/kimai/releases/tag/1.6.2)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- Invoice changes:
- Moved CSV, ODS and XSLX invoice templates to [another repository](https://github.com/Keleo/kimai2-invoice-templates). Using them? Install them manually (see [invoice documentation](https://www.kimai.org/documentation/invoices.html)).
- Added new invoice fields (VAT, contact, payment details) and customer field (VAT). Used the twig settings before? Move them to the respective invoice template settings.
- Permissions can be managed via Admin UI. Please move your permission settings from [local.yaml to your database](https://www.kimai.org/documentation/permissions.html).
- Important permission change: regular users with the `view_other_timesheet` permission could see all timesheets. This was a legacy from the time before team permissions were introduced. If you rely on this behavior, you need to create a team with all users and the teamlead being the user who needs access to all timesheets.
### Developer
Please add default permissions to your [plugin](https://www.kimai.org/documentation/plugins.html).
## [1.5](https://github.com/kimai/kimai/releases/tag/1.5)
[Update as usual](https://www.kimai.org/documentation/updates.html)
## [1.4](https://github.com/kimai/kimai/releases/tag/1.4)
**There is a new directory, which needs to be writable by the webserver: `public/avatars/`.**
New permission (used in new dashboard widget):
- `view_team_member` - display team assignments (names, teamleads and members) for the current user
Activated Javascript select component by default (check mobile devices).
### Developer: BC breaks
- Dashboard widgets and rows need to define their `type` by FQCN
- Switched to Symfony 4.3 event types, this could fail in plugins, but only if they didn't use the official constants for event names
## [1.3](https://github.com/kimai/kimai/releases/tag/1.3)
Added `manage_tag` permission for new tag features
### Developer: BC breaks
- Refactored toolbars and search, plugins needs to be checked
- Invoices now supports multiple repositories, some method signatures had to be changed (eg. `calculateSumIdentifier()`)
## [1.2](https://github.com/kimai/kimai/releases/tag/1.2)
**If you are still using 0.7 or below, you need to upgrade to 1.1 before upgrading to this version.**
- Deleted timezone conversion command.
- Minimum password length raised from 5 to 8 character (applies only for password changes and new users)
- Maximum customer name length lowered to 150 character
- Maximum project name length lowered to 150 character
- Maximum activity name length lowered to 150 character
- Added new permission: `manage_invoice_template`
- Removed permissions: `view_invoice_template`, `create_invoice_template`, `edit_invoice_template`, `delete_invoice_template`
- Removed permission: `view_export` (using `create_export` only)
### Developer: BC breaks
- Custom export renderer need to check for usage of `Timesheet::getEnd()` as running entries can now be exported as well
## [1.1](https://github.com/kimai/kimai/releases/tag/1.1)
[Update as usual](https://www.kimai.org/documentation/updates.html), nothing special for this release if you upgrade from 1.0 / 1.0.1.
## [1.0](https://github.com/kimai/kimai/releases/tag/1.0)
This release contains several changes, as I still have the goal to stabilize the code base to prevent
such "challenges" after 1.0 for a while.
### Changes for your local.yaml
New permissions are available. You have to add them to your `local.yaml` ONLY if you use a custom permission structure,
otherwise you can't use the new features:
- `view_tag` - view all tags
- `delete_tag` - delete tags
- `edit_exported_timesheet` - allows to edit records which were exported
- `role_permissions` - view calculated permissions for user roles
- `budget_activity` - view and edit budgets for activities
- `budget_project` - view and edit budgets for projects
- `budget_customer` - view and edit budgets for customers
Removed permission:
- `system_actions` - removed experimental feature to flush app cache from the about screen
### BC BREAKS
- API: Format for queries including a datetime object fixed to use HTML5 format (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00`)
- **Permission config**: the `permissions` definition in your `local.yaml` needs to be verified/changed, as the internal structure was highly optimized to simplify the definition.
Thanks to the new structure, you should be able to remove almost everything from your `local.yaml` (tip: start over from scratch!). Please read [the updated permission docu](https://www.kimai.org/documentation/permissions.html).
- default widgets were removed from `kimai.yaml`, that shouldn't cause any issues ... but if something is odd: [look here for help](https://www.kimai.org/documentation/dashboard.html)
## [0.9](https://github.com/kimai/kimai/releases/tag/0.9)
Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
### BC BREAKS
This release contains some BC breaks which were necessary before 1.0 will be released (_now or never_), to prevent those BC breaks after 1.0.
- **Kimai requires PHP 7.2 now => [PHP 7.1 expired 4 month ago](https://www.php.net/supported-versions.php)**
- The `.env` variable `DATABASE_PREFIX` was removed and the table prefix is now hardcoded to `kimai2_`. If you used another prefix,
you have to rename your tables manually before starting the update process. You can delete the row `DATABASE_PREFIX` from your `.env` file.
- API: Format for DateTime objects changed, now including timezone identifier (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00+00:00`), see [#718](https://github.com/kimai/kimai/pull/718)
- API: changed from snake_case to camelCase (affected fields: hourlyRate vs hourly_rate / fixedRate vs fixed_rate / orderNumber vs order_number / i18n config object)
- Plugin mechanism changed: existing Plugins have to be deleted or updated
### Apply necessary changes to your `local.yaml`:
New permissions are available:
- `system_configuration` - for accessing the new system configuration screen
- `system_actions` - for the experimental feature to flush your cache from the about screen
- `plugins` - for accessing the new plugins screen
The setting `kimai.timesheet.mode` replaces the setting `kimai.timesheet.duration_only`. If you used the duration_only mode, you need to change your config:
```yaml
# Before
kimai:
timesheet:
duration_only: true
# After
kimai:
timesheet:
mode: duration_only
```
Or switch the mode directly in the new System configuration screen within Kimai.
## [0.8.1](https://github.com/kimai/kimai/releases/tag/0.8.1)
A bug fixing release. Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
## [0.8](https://github.com/kimai/kimai/releases/tag/0.8)
After you followed the normal update and database migration process (see above), you need to execute a bash command to convert your timesheet data for timezone support:
- Read this [pull request](https://github.com/kimai/kimai/pull/372) BEFORE you follow the instructions to convert the
timezones in your existing time records with `bin/console kimai:convert-timezone`. Without that, you will end up with wrong times in your database.
### Apply necessary changes to your `local.yaml`:
- A new boolean setting `kimai.timesheet.rules.allow_future_times` was introduced
- New permissions are available:
- `view_export` - for the new export feature
- `create_export` - for the new export feature
- `edit_export_own_timesheet` - for the new export feature
- `edit_export_other_timesheet` - for the new export feature
- `system_information` - to see the new about screen
## [0.7](https://github.com/kimai/kimai/releases/tag/0.7)
The configuration `kimai.theme.active_warning` was deprecated and should be replaced in your local.yaml,
[read config docs for more information](https://www.kimai.org/documentation/timesheet.html#limit-active-entries).
## [0.6.1](https://github.com/kimai/kimai/releases/tag/0.6.1)
A bugfix release to address database compatibility issues with older MySQL/MariaDB versions.
## [0.6](https://github.com/kimai/kimai/releases/tag/0.6)
The API has some minor BC breaks: some fields were renamed and entities have a larger attribute set than collections.
Be aware that the API is still is development mode and shouldn't be considered stable for now.
## [0.5](https://github.com/kimai/kimai/releases/tag/0.5)
Some configuration nodes were removed, if you have one of them in your `local.yaml` you need to delete them before you start the update:
- `kimai.invoice.calculator`
- `kimai.invoice.renderer`
- `kimai.invoice.number_generator`
The new config `kimai.invoice.documents` was introduced, holding a list of directories ([read more](https://www.kimai.org/documentation/invoices.html)).
**BC break:** InvoiceTemplate name was changed from 255 characters to 60. If you used longer invoice-template names, they will be truncated when upgrading the database.
Please make sure that they are unique in the first 60 character before you upgrade your database with `doctrine:migrations:migrate`.
## [0.4](https://github.com/kimai/kimai/releases/tag/0.4)
In the time between 0.3 and 0.4 there was a release of composer that introduced a BC break,
which leads to problems between Composer and Symfony Flex, resulting in an error like this when running it:
```
[ErrorException]
Declaration of Symfony\Flex\ParallelDownloader::getRemoteContents($originUrl, $fileUrl, $context) should be compatible with Composer\Util\RemoteFilesystem::getRemoteContents($originUrl, $fileUrl, $context, ?array &$responseHeaders = NULL)
```
This can be fixed by updating Composer and Flex before executing the Kimai update:
```
sudo composer self-update
sudo -u www-data composer update symfony/flex --no-plugins --no-scripts
```
## [0.3](https://github.com/kimai/kimai/releases/tag/0.3)
You need to adjust your `.env` file and add your `from` address for [all emails](https://www.kimai.org/documentation/emails.html) generated by Kimai 2:
```
MAILER_FROM=kimai@example.com
```
Create a file and database backup before executing the following steps:
```bash
git pull origin master
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data bin/console cache:clear --env=prod
sudo -u www-data bin/console cache:warmup --env=prod
bin/console doctrine:migrations:version --add 20180701120000
bin/console doctrine:migrations:migrate
```

View File

@@ -1,4 +1,4 @@
# Upgrading Kimai
# Upgrading Kimai - Version2.x
_Make sure to create a backup before you start!_
@@ -8,21 +8,31 @@ you can upgrade your Kimai installation to the latest stable release.
Check below if there are more version specific steps required, which need to be executed after the normal update process.
Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation.
## [2.0.30](https://github.com/kimai/kimai/releases/tag/2.0.30)
The `DATABASE_URL` in your environment settings (e.g. [.env](https://github.com/kimai/kimai/issues/4246), [docker-compose.yaml](https://github.com/tobybatch/kimai2/issues/531) or webserver config)
now requires the `charset` and `serverVersion` params, e.g.: `DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB` (examples in `.env`).
## [2.0](https://github.com/kimai/kimai/releases/tag/2.0)
**!! This release requires minimum PHP version to 8.1 !!**
### Breaking changes
- All plugins need to be updated: delete all previous version from your installation (`rm -r var/plugins/*`) before updating!
- The `local.yaml` is not compatible with old version, remove it before the update and then re-create it after everything works
- removed: configuring the `dashboard` is not supported any longer
- removed: custom translation files via `theme.branding.translation`
- removed: changing the plugin directory via `kimai.plugin_dir`
### Developer
Developer read the full documentation at [https://www.kimai.org/documentation/migration-v2.html](https://www.kimai.org/documentation/migration-v2.html).
- **All plugins need to be updated**: delete all previous version from your installation (`rm -r var/plugins/*`) before updating!
- Invoice renderer and templates for XML, JSON and TEXT were moved to the [Extended invoicing plugin](https://www.kimai.org/store/invoice-bundle.html) (install if you use one of those)
- Moved `company.docx` to [external repo](https://github.com/kimai/invoice-templates/tree/main/docx-company) (needs to be re-uploaded if you want to keep on using it!)
- Role names are forced to be uppercase
- Removed unused `public/avatars/` directory
- `local.yaml` is not compatible with old version, remove it before the update and then re-create it after everything works
- dashboard default config
- removed: theme.branding.translation
- removed: kimai.plugin_dir
- Time-tracking mode `duration_only` was removed, existing installations will be switched to `duration_fixed_begin`
- Removed Twig filters. You might have to replace them in your custom export/invoice templates:
- `date_full` => `date_time`
@@ -38,362 +48,3 @@ Developer read the full documentation at [https://www.kimai.org/documentation/mi
- `composer require symfony/mailgun-mailer`
- `composer require symfony/postmark-mailer`
- `composer require symfony/sendgrid-mailer`
## [1.16](https://github.com/kimai/kimai/releases/tag/1.16)
If you are using MariaDB, it must be at least version 10.1, older versions are not supported any longer.
**DEVELOPER**
- Removed `formDateTime` field from API model `I18nConfig`
- Upgraded to Doctrine DBAL 3, see [docs](https://github.com/doctrine/dbal/blob/3.1.x/UPGRADE.md) - you might have to update your bundle
## [1.15](https://github.com/kimai/kimai/releases/tag/1.15)
**Many database changes: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Updating the database might take quite a while, depending on the amount of timesheet entries and speed of your database server (~1 minute per 100k records).
**ATTENTION**
- This release bumps the minimum required [PHP version to 7.3](https://www.kimai.org/blog/2021/php8-support-php72-dropped/)
- Self-registration is disabled by default
- Self-registration now always requires email confirmation
- All plugins that use own databases need to be updated as well
- Removed the YearChart widget and the related configs named `userRecapThisYear`, `userRecapLastYear`, `userRecapTwoYears`, `userRecapThreeYears`
**LDAP & SAML**
Please verify your config with the [LDAP](https://www.kimai.org/documentation/ldap.html) and [SAML](https://www.kimai.org/documentation/saml.html) documentation, especially:
- SAML users: activate it by setting the `kimai.saml.activate: true` config key
- LDAP users: activate it by setting the `kimai.ldap.activate: true` config key
- LDAP and SAML users need to remove the complete `security` section from their `local.yaml`
**DEVELOPER**
PHP 8 compatibility forced to upgrade MANY libraries, including but not limited to:
- Removed FOSUserBundle and hslavich/oneloginsaml
- Doctrine Migrations, whose new major version forces plugin updates
- Gedmo v3 (which include BC breaks in definitions)
- Doctrine DBAL and others, which required PHP 7.3 as well
**API BC break**: Due to team structure changes, it was impossible to keep the (writing) API structure. Please adjust your code accordingly!
## [1.14](https://github.com/kimai/kimai/releases/tag/1.14)
**CRITICAL BC break**: SQLite support was removed. If you are using SQLite, you have to [read this blog post](https://www.kimai.org/blog/2021/sqlite-and-ftp-support-removed/) and migrate to MySQL/MariaDB first!
**New database tables and fields: don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
Permission changes:
- `history_invoice` - removed permission entirely
## [1.13](https://github.com/kimai/kimai/releases/tag/1.13)
- Deprecated `now` variable in export templates: create it yourself with `{% set now = create_date('now', app.user) %}`
- Changed invoice filename generation (check if you use cronjob for invoices)
- **BC break**: duration entered as plain numbers will now be treated as decimal duration in hours instead of seconds
## [1.12](https://github.com/kimai/kimai/releases/tag/1.12)
- Export templates can now include items from plugins (eg. Expenses).
## [1.10](https://github.com/kimai/kimai/releases/tag/1.10)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- Invoice renderer `CSV` was removed
- Sessions are now stored in the database (all users have to re-login after upgrade)
- New permissions: `lockdown_grace_timesheet`, `lockdown_override_timesheet`, `view_all_data`
- Fixed team permissions on user queries: depending on your previous team & permission setup your users might see less data (SUPER_ADMINS see all data, but new: ADMINS only see all data if they own the `view_all_data` permission)
- Markdown does not support headings anymore, text like `# foo` is not converted to `<h1 id="foo">foo</h1>` anymore
### Developer
- **BC break**: removed registration of `.env` with `putenv()` - do not rely on `getenv()` as it is not thread-safe
- **BC break**: interface method signature `HtmlToPdfConverter::convertToPdf()` changed
- **BC break**: the macros `badge` and `label` do not apply the `|trans` filter any more
- **BC Break**: removed `getVisible()` (deprecated since 1.4) method on Customer, Project and Activity (use `isVisible()` instead, templates are still working)
- **BC Break**: API changes
- some representation names changed (eg. from `ActivityMetaField` to `ActivityMeta`, `TimesheetSubCollection` vs `TimesheetCollectionExpanded`), you could use `class_alias()` if you use auto-generated code from Swagger-Gen or alike
- new result types were introduced
- result data changed in some areas to smooth out inconsistencies (eg. TeamEntity fields changed in nested results)
## [1.9](https://github.com/kimai/kimai/releases/tag/1.9)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- The directory `var/data/invoices/` will be used to store archived invoice files (check file permissions)
- The default invoice number format changed. If you want to use the old one: configure `{date}` as format - see [invoice documentation](https://www.kimai.org/documentation/invoices.html)
- HTML invoice templates are now treated like other files and offered as download. If you are using relative URLs for including assets (CSS, images) you need to either inline them (see the default templates) or use absolute URLs
- Invoice templates that use the templates variables `${activity.X}` or `${project.X}` should be checked and possibly adapted, as multi-select is now possible for filtering
- Invoice templates have access to all meta-fields as variables, not only the ones marked as visible
- Rates configuration/structure changed for customer, project and activity
- **Invoice templates**: rates variables were removed
Permission changes:
- `history_invoice` - NEW: grants all features for the new invoice archive (by default for all admins)
### Developer
- **BC break**: `InvoiceItemInterface` has new methods `getType()` and `getCategory()`
- **BC break**: API fields changed - see new `/rates` endpoints
## [1.8](https://github.com/kimai/kimai/releases/tag/1.8)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- New PHP requirement: `ext-xsl` - which should be pre-installed in most environments when `ext-xml` is loaded
- New mailer library: check if emails are still working (eg. by using the "password forgotten" function) or if you need to adjust your configuration, [see docs at symfony.com](https://symfony.com/doc/current/components/mailer.html#transport)
- Support for line breaks in multiline invoice fields for spreadsheets (check your invoice templates after the update)
Permission changes:
- `comments_create_customer` - NEW: permission that allows to add new comments for customers
- `comments_create_team_customer` - NEW: permission that allows to add new comments for team members of the current customer
- `comments_create_teamlead_customer` - NEW: permission that allows to add new comments for a teamlead of the current customer
- `comments_create_project` - NEW: permission that allows to add new comments for project
- `comments_create_team_project` - NEW: permission that allows to add new comments for team members of the current project
- `comments_create_teamlead_project` - NEW: permission that allows to add new comments for a teamlead of the current project
- `edit_teamlead_project` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `edit_teamlead_customer` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
- `upload_invoice_template` - NEW: permission that allows to upload invoice documents from the UI
## [1.7](https://github.com/kimai/kimai/releases/tag/1.7)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
New permissions:
- `comments_customer` - show comment list on customer detail page (new feature)
- `details_customer` - show detail information for customers (customer number, vat, rates, meta-fields, assigned teams ...)
- `comments_project` - show comment list on project detail page (new feature)
- `details_project` - show detail information for projects (rates, meta-fields, assigned teams ...)
If you are using teams, please read on: The following list of permissions are now also available in the UI and they (can) replace the `X_project` and `X_customer` permissions.
They are more strict, as they allow only access to team specific items, the older permissions without `_teamlead_`/`_team_` work on a global level instead.
- `view_teamlead_customer`, `edit_teamlead_customer`, `budget_teamlead_customer`, `permissions_teamlead_customer`, `comments_teamlead_customer`, `details_teamlead_customer` - allows access to customer data when user is teamlead of a team assigned to the customer (replaces more global permission like `view_customer` for teamleads)
- `view_team_customer`, `edit_team_customer`, `budget_team_customer`, `comments_team_customer`, `details_team_customer` - allows access to customer data when user is member of a team assigned to the customer (replaces more global permission like `view_customer` for users)
- `view_teamlead_project`, `edit_teamlead_project`, `budget_teamlead_project`, `permissions_teamlead_project`, `comments_teamlead_project`, `details_teamlead_project` - allows access to customer data when user is teamlead of a team assigned to the project (replaces more global permission like `view_project` for teamleads)
- `view_team_project`, `edit_team_project`, `budget_team_project`, `comments_team_project`, `details_team_project` - allows access to customer data when user is member of a team assigned to the project (replaces more global permission like `view_project` for users)
### ExpenseBundle
**ATTENTION** due to incompatibilities in the underlying frameworks users of the ExpenseBundle need to do one more step:
You need to delete the bundle before updating: `rm -r var/plugins/ExpenseBundle`, otherwise you will run into errors during the update.
After the Kimai update was successful, you have to re-install the latest bundle version, which is compatible with Kimai 1.7 only.
### Developer
- Projects now have a start and end date and the API will only return those, which are either unconfigured or currently active, you might want to reload the list of projects once the user entered begin and end datetime OR use the new `ignoreDates` parameter.
- Doctrine bundle was updated to v2, check your code for [the usage of RegistryInterface and ObjectManager](https://github.com/doctrine/DoctrineBundle/blob/master/UPGRADE-2.0.md)
- Removed the webserver bundle and the command `server:run` - see [docs](https://www.kimai.org/documentation/developers.html)
## [1.6](https://github.com/kimai/kimai/releases/tag/1.6), [1.6.1](https://github.com/kimai/kimai/releases/tag/1.6.1), [1.6.2](https://github.com/kimai/kimai/releases/tag/1.6.2)
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
- Invoice changes:
- Moved CSV, ODS and XSLX invoice templates to [another repository](https://github.com/Keleo/kimai2-invoice-templates). Using them? Install them manually (see [invoice documentation](https://www.kimai.org/documentation/invoices.html)).
- Added new invoice fields (VAT, contact, payment details) and customer field (VAT). Used the twig settings before? Move them to the respective invoice template settings.
- Permissions can be managed via Admin UI. Please move your permission settings from [local.yaml to your database](https://www.kimai.org/documentation/permissions.html).
- Important permission change: regular users with the `view_other_timesheet` permission could see all timesheets. This was a legacy from the time before team permissions were introduced. If you rely on this behavior, you need to create a team with all users and the teamlead being the user who needs access to all timesheets.
### Developer
Please add default permissions to your [plugin](https://www.kimai.org/documentation/plugins.html).
## [1.5](https://github.com/kimai/kimai/releases/tag/1.5)
[Update as usual](https://www.kimai.org/documentation/updates.html)
## [1.4](https://github.com/kimai/kimai/releases/tag/1.4)
**There is a new directory, which needs to be writable by the webserver: `public/avatars/`.**
New permission (used in new dashboard widget):
- `view_team_member` - display team assignments (names, teamleads and members) for the current user
Activated Javascript select component by default (check mobile devices).
### Developer: BC breaks
- Dashboard widgets and rows need to define their `type` by FQCN
- Switched to Symfony 4.3 event types, this could fail in plugins, but only if they didn't use the official constants for event names
## [1.3](https://github.com/kimai/kimai/releases/tag/1.3)
Added `manage_tag` permission for new tag features
### Developer: BC breaks
- Refactored toolbars and search, plugins needs to be checked
- Invoices now supports multiple repositories, some method signatures had to be changed (eg. `calculateSumIdentifier()`)
## [1.2](https://github.com/kimai/kimai/releases/tag/1.2)
**If you are still using 0.7 or below, you need to upgrade to 1.1 before upgrading to this version.**
- Deleted timezone conversion command.
- Minimum password length raised from 5 to 8 character (applies only for password changes and new users)
- Maximum customer name length lowered to 150 character
- Maximum project name length lowered to 150 character
- Maximum activity name length lowered to 150 character
- Added new permission: `manage_invoice_template`
- Removed permissions: `view_invoice_template`, `create_invoice_template`, `edit_invoice_template`, `delete_invoice_template`
- Removed permission: `view_export` (using `create_export` only)
### Developer: BC breaks
- Custom export renderer need to check for usage of `Timesheet::getEnd()` as running entries can now be exported as well
## [1.1](https://github.com/kimai/kimai/releases/tag/1.1)
[Update as usual](https://www.kimai.org/documentation/updates.html), nothing special for this release if you upgrade from 1.0 / 1.0.1.
## [1.0](https://github.com/kimai/kimai/releases/tag/1.0)
This release contains several changes, as I still have the goal to stabilize the code base to prevent
such "challenges" after 1.0 for a while.
### Changes for your local.yaml
New permissions are available. You have to add them to your `local.yaml` ONLY if you use a custom permission structure,
otherwise you can't use the new features:
- `view_tag` - view all tags
- `delete_tag` - delete tags
- `edit_exported_timesheet` - allows to edit records which were exported
- `role_permissions` - view calculated permissions for user roles
- `budget_activity` - view and edit budgets for activities
- `budget_project` - view and edit budgets for projects
- `budget_customer` - view and edit budgets for customers
Removed permission:
- `system_actions` - removed experimental feature to flush app cache from the about screen
### BC BREAKS
- API: Format for queries including a datetime object fixed to use HTML5 format (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00`)
- **Permission config**: the `permissions` definition in your `local.yaml` needs to be verified/changed, as the internal structure was highly optimized to simplify the definition.
Thanks to the new structure, you should be able to remove almost everything from your `local.yaml` (tip: start over from scratch!). Please read [the updated permission docu](https://www.kimai.org/documentation/permissions.html).
- default widgets were removed from `kimai.yaml`, that shouldn't cause any issues ... but if something is odd: [look here for help](https://www.kimai.org/documentation/dashboard.html)
## [0.9](https://github.com/kimai/kimai/releases/tag/0.9)
Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
### BC BREAKS
This release contains some BC breaks which were necessary before 1.0 will be released (_now or never_), to prevent those BC breaks after 1.0.
- **Kimai requires PHP 7.2 now => [PHP 7.1 expired 4 month ago](https://www.php.net/supported-versions.php)**
- The `.env` variable `DATABASE_PREFIX` was removed and the table prefix is now hardcoded to `kimai2_`. If you used another prefix,
you have to rename your tables manually before starting the update process. You can delete the row `DATABASE_PREFIX` from your `.env` file.
- API: Format for DateTime objects changed, now including timezone identifier (previously `2019-03-02 14:23` - now `2019-03-02T14:23:00+00:00`), see [#718](https://github.com/kimai/kimai/pull/718)
- API: changed from snake_case to camelCase (affected fields: hourlyRate vs hourly_rate / fixedRate vs fixed_rate / orderNumber vs order_number / i18n config object)
- Plugin mechanism changed: existing Plugins have to be deleted or updated
### Apply necessary changes to your `local.yaml`:
New permissions are available:
- `system_configuration` - for accessing the new system configuration screen
- `system_actions` - for the experimental feature to flush your cache from the about screen
- `plugins` - for accessing the new plugins screen
The setting `kimai.timesheet.mode` replaces the setting `kimai.timesheet.duration_only`. If you used the duration_only mode, you need to change your config:
```yaml
# Before
kimai:
timesheet:
duration_only: true
# After
kimai:
timesheet:
mode: duration_only
```
Or switch the mode directly in the new System configuration screen within Kimai.
## [0.8.1](https://github.com/kimai/kimai/releases/tag/0.8.1)
A bug fixing release. Remember to execute the necessary timezone conversion script, if you haven't updated to 0.8 before (see below)!
## [0.8](https://github.com/kimai/kimai/releases/tag/0.8)
After you followed the normal update and database migration process (see above), you need to execute a bash command to convert your timesheet data for timezone support:
- Read this [pull request](https://github.com/kimai/kimai/pull/372) BEFORE you follow the instructions to convert the
timezones in your existing time records with `bin/console kimai:convert-timezone`. Without that, you will end up with wrong times in your database.
### Apply necessary changes to your `local.yaml`:
- A new boolean setting `kimai.timesheet.rules.allow_future_times` was introduced
- New permissions are available:
- `view_export` - for the new export feature
- `create_export` - for the new export feature
- `edit_export_own_timesheet` - for the new export feature
- `edit_export_other_timesheet` - for the new export feature
- `system_information` - to see the new about screen
## [0.7](https://github.com/kimai/kimai/releases/tag/0.7)
The configuration `kimai.theme.active_warning` was deprecated and should be replaced in your local.yaml,
[read config docs for more information](https://www.kimai.org/documentation/timesheet.html#limit-active-entries).
## [0.6.1](https://github.com/kimai/kimai/releases/tag/0.6.1)
A bugfix release to address database compatibility issues with older MySQL/MariaDB versions.
## [0.6](https://github.com/kimai/kimai/releases/tag/0.6)
The API has some minor BC breaks: some fields were renamed and entities have a larger attribute set than collections.
Be aware that the API is still is development mode and shouldn't be considered stable for now.
## [0.5](https://github.com/kimai/kimai/releases/tag/0.5)
Some configuration nodes were removed, if you have one of them in your `local.yaml` you need to delete them before you start the update:
- `kimai.invoice.calculator`
- `kimai.invoice.renderer`
- `kimai.invoice.number_generator`
The new config `kimai.invoice.documents` was introduced, holding a list of directories ([read more](https://www.kimai.org/documentation/invoices.html)).
**BC break:** InvoiceTemplate name was changed from 255 characters to 60. If you used longer invoice-template names, they will be truncated when upgrading the database.
Please make sure that they are unique in the first 60 character before you upgrade your database with `doctrine:migrations:migrate`.
## [0.4](https://github.com/kimai/kimai/releases/tag/0.4)
In the time between 0.3 and 0.4 there was a release of composer that introduced a BC break,
which leads to problems between Composer and Symfony Flex, resulting in an error like this when running it:
```
[ErrorException]
Declaration of Symfony\Flex\ParallelDownloader::getRemoteContents($originUrl, $fileUrl, $context) should be compatible with Composer\Util\RemoteFilesystem::getRemoteContents($originUrl, $fileUrl, $context, ?array &$responseHeaders = NULL)
```
This can be fixed by updating Composer and Flex before executing the Kimai update:
```
sudo composer self-update
sudo -u www-data composer update symfony/flex --no-plugins --no-scripts
```
## [0.3](https://github.com/kimai/kimai/releases/tag/0.3)
You need to adjust your `.env` file and add your `from` address for [all emails](https://www.kimai.org/documentation/emails.html) generated by Kimai 2:
```
MAILER_FROM=kimai@example.com
```
Create a file and database backup before executing the following steps:
```bash
git pull origin master
sudo -u www-data composer install --no-dev --optimize-autoloader
sudo -u www-data bin/console cache:clear --env=prod
sudo -u www-data bin/console cache:warmup --env=prod
bin/console doctrine:migrations:version --add 20180701120000
bin/console doctrine:migrations:migrate
```

1
assets/app-rtl.js Normal file
View File

@@ -0,0 +1 @@
require('./sass/_app-rtl.scss');

View File

@@ -1,5 +1,5 @@
require('./sass/app.scss');
require('./sass/_app.scss');
// ------ Kimai itself ------
require('./js/KimaiWebLoader.js');

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

@@ -1,2 +1,2 @@
require('./sass/export-pdf.scss');
require('./sass/_export-pdf.scss');

View File

@@ -1,2 +1,2 @@
require('./sass/invoice-pdf.scss');
require('./sass/_invoice-pdf.scss');

View File

@@ -1,2 +1,2 @@
require('./sass/invoice.scss');
require('./sass/_invoice.scss');

View File

@@ -88,4 +88,11 @@ export default class KimaiContainer {
return this._configuration;
}
/**
* @returns {KimaiUser}
*/
getUser() {
return this.getPlugin('user');
}
}

View File

@@ -41,6 +41,8 @@ import KimaiDateNowForm from "./forms/KimaiDateNowForm";
import KimaiNotification from "./plugins/KimaiNotification";
import KimaiHotkeys from "./plugins/KimaiHotkeys";
import KimaiRemoteModal from "./plugins/KimaiRemoteModal";
import KimaiUser from "./plugins/KimaiUser";
import KimaiAutocompleteTags from "./forms/KimaiAutocompleteTags";
export default class KimaiLoader {
@@ -55,6 +57,7 @@ export default class KimaiLoader {
);
// GLOBAL HELPER PLUGINS
kimai.registerPlugin(new KimaiUser());
kimai.registerPlugin(new KimaiEscape());
kimai.registerPlugin(new KimaiEvent());
kimai.registerPlugin(new KimaiAPI());
@@ -68,6 +71,7 @@ export default class KimaiLoader {
kimai.registerPlugin(new KimaiDateRangePicker('input[data-daterangepicker="on"]'));
kimai.registerPlugin(new KimaiDatePicker('input[data-datepicker="on"]'));
kimai.registerPlugin(new KimaiAutocomplete());
kimai.registerPlugin(new KimaiAutocompleteTags());
kimai.registerPlugin(new KimaiTimesheetForm());
kimai.registerPlugin(new KimaiTeamForm());
kimai.registerPlugin(new KimaiCopyDataForm());
@@ -81,7 +85,7 @@ export default class KimaiLoader {
kimai.registerPlugin(new KimaiDatatable('section.content', 'table.dataTable'));
kimai.registerPlugin(new KimaiToolbar('form.searchform', 'toolbar-action'));
kimai.registerPlugin(new KimaiAlternativeLinks('.alternative-link'));
kimai.registerPlugin(new KimaiAjaxModalForm('.modal-ajax-form'));
kimai.registerPlugin(new KimaiAjaxModalForm('.modal-ajax-form', ['td.multiCheckbox', 'td.actions']));
kimai.registerPlugin(new KimaiRemoteModal());
kimai.registerPlugin(new KimaiActiveRecords());
kimai.registerPlugin(new KimaiAPILink('api-link'));

View File

@@ -6,13 +6,12 @@
*/
import TomSelect from 'tom-select';
import KimaiFormPlugin from "./KimaiFormPlugin";
import KimaiFormTomselectPlugin from "./KimaiFormTomselectPlugin";
/**
* Supporting auto-complete fields via API.
* Used for timesheet tagging in toolbar and edit dialogs.
*/
export default class KimaiAutocomplete extends KimaiFormPlugin {
export default class KimaiAutocomplete extends KimaiFormTomselectPlugin {
init()
{
@@ -28,11 +27,23 @@ export default class KimaiAutocomplete extends KimaiFormPlugin {
return true;
}
activateForm(form)
{
loadData(apiUrl, query, callback) {
/** @type {KimaiAPI} API */
const API = this.getContainer().getPlugin('api');
API.get(apiUrl, {'name': query}, (data) => {
let results = [];
for (let item of data) {
results.push({text: item.name, value: item.name});
}
callback(results);
}, () => {
callback();
});
}
activateForm(form)
{
[].slice.call(form.querySelectorAll(this.selector)).map((node) => {
const apiUrl = node.dataset['autocompleteUrl'];
let minChars = 3;
@@ -40,7 +51,12 @@ export default class KimaiAutocomplete extends KimaiFormPlugin {
minChars = parseInt(node.dataset['minimumCharacter']);
}
new TomSelect(node, {
let options = {
// see https://github.com/orchidjs/tom-select/issues/543#issuecomment-1664342257
onItemAdd: function(){
// remove remaining characters from input after selecting an item
this.setTextboxValue('');
},
// if there are more than 500, they need to be found by "typing"
maxOptions: 500,
// the autocomplete is ONLY used, when the user can create tags
@@ -53,36 +69,21 @@ export default class KimaiAutocomplete extends KimaiFormPlugin {
return query.length >= minChars;
},
load: (query, callback) => {
API.get(apiUrl, {'name': query}, (data) => {
const results = [].slice.call(data).map((result) => {
return {text: result, value: result};
});
callback(results);
}, () => {
callback();
});
this.loadData(apiUrl, query, callback);
},
render: {
// eslint-disable-next-line
not_loading: (data, escape) => {
// no default content
},
option_create: (data, escape) => {
const name = escape(data.input);
if (name.length < 3) {
return null;
}
const tpl = this.translate('select.search.create');
const tplReplaced = tpl.replace('%input%', '<strong>' + name + '</strong>')
return '<div class="create">' + tplReplaced + '</div>';
},
no_results: (data, escape) => {
const tpl = this.translate('select.search.notfound');
const tplReplaced = tpl.replace('%input%', '<strong>' + escape(data.input) + '</strong>')
return '<div class="no-results">' + tplReplaced + '</div>';
},
};
let render = {
// eslint-disable-next-line
not_loading: (data, escape) => {
// no default content
},
});
};
const rendererType = (node.dataset['renderer'] !== undefined) ? node.dataset['renderer'] : 'default';
options.render = {...render, ...this.getRenderer(rendererType)};
new TomSelect(node, options);
});
}

View File

@@ -0,0 +1,34 @@
/*
* 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.
*/
import KimaiAutocomplete from "./KimaiAutocomplete";
/**
* Used for timesheet tagging in toolbar and edit dialogs.
*/
export default class KimaiAutocompleteTags extends KimaiAutocomplete {
init()
{
this.selector = '[data-form-widget="tags"]';
}
loadData(apiUrl, query, callback) {
/** @type {KimaiAPI} API */
const API = this.getContainer().getPlugin('api');
API.get(apiUrl, {'name': query}, (data) => {
let results = [];
for (let item of data) {
results.push({text: item.name, value: item.name, color: item['color-safe']});
}
callback(results);
}, () => {
callback();
});
}
}

View File

@@ -57,6 +57,16 @@ export default class KimaiDatePicker extends KimaiFormPlugin {
if (element.dataset.format === undefined) {
console.log('Trying to bind litepicker to an element without data-format attribute');
}
if (element.hasAttribute('min') !== undefined) {
options = {...options, ...{
'minDate': element.getAttribute('min'),
}};
}
if (element.hasAttribute('max') !== undefined) {
options = {...options, ...{
'maxDate': element.getAttribute('max'),
}};
}
options = {...options, ...{
format: element.dataset.format,
showTooltip: false,
@@ -66,7 +76,7 @@ export default class KimaiDatePicker extends KimaiFormPlugin {
firstDay: FIRST_DOW, // Litepicker: 0 = Sunday, 1 = Monday
setup: (picker) => {
// nasty hack, because litepicker does not trigger change event on the input and the available
// event "selected" is triggered why to often, even when moving the cursor inside the input
// event "selected" is triggered way to often, even when moving the cursor inside the input
// element (not even typing is necessary) and so we have to make sure that the manual "click" event
// (works for touch as well) happened before we actually dispatch the change event manually ...
// what? report forms would be submitted upon cursor move without the "preselect” check
@@ -79,6 +89,12 @@ export default class KimaiDatePicker extends KimaiFormPlugin {
delete picker._wasPreselected;
}
});
// only if mobile.friendly plugin is activated
if (picker.backdrop !== undefined) {
// the node needs to be moved, so the flat form layout works properly (e.g. for date types)
document.body.appendChild(picker.backdrop);
}
},
}};

View File

@@ -10,9 +10,9 @@
*/
import TomSelect from 'tom-select';
import KimaiFormPlugin from "./KimaiFormPlugin";
import KimaiFormTomselectPlugin from "./KimaiFormTomselectPlugin";
export default class KimaiFormSelect extends KimaiFormPlugin {
export default class KimaiFormSelect extends KimaiFormTomselectPlugin {
constructor(selector, apiSelects)
{
@@ -52,6 +52,15 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
let plugins = ['change_listener'];
const isMultiple = node.multiple !== undefined && node.multiple === true;
const isRequired = node.required !== undefined && node.required === true;
if (isRequired) {
plugins.push('no_backspace_delete');
}
if (isMultiple) {
plugins.push('remove_button');
}
/*
const isOrdering = false;
@@ -61,39 +70,32 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
}
*/
if (isMultiple) {
plugins.push('remove_button');
}
let options = {
// see https://github.com/orchidjs/tom-select/issues/543#issuecomment-1664342257
onItemAdd: function(){
// remove remaining characters from input after selecting an item
this.setTextboxValue('');
},
lockOptgroupOrder: true,
allowEmptyOption: true,
allowEmptyOption: !isRequired,
hidePlaceholder: false,
plugins: plugins,
// if there are more than X entries, the other ones are hidden and can only be found
// by typing some characters to trigger the internal option search
// see App\Form\Type\TagsType::MAX_AMOUNT_SELECT
maxOptions: 500,
sortField:[{field: '$order'}, {field: '$score'}],
};
let render = {
option_create: (data, escape) => {
const name = escape(data.input);
if (name.length < 3) {
return null;
}
const tpl = this.translate('select.search.create');
const tplReplaced = tpl.replace('%input%', '<strong>' + name + '</strong>');
return '<div class="create">' + tplReplaced + '</div>';
},
no_results: (data, escape) => {
const tpl = this.translate('select.search.notfound');
const tplReplaced = tpl.replace('%input%', '<strong>' + escape(data.input) + '</strong>');
return '<div class="no-results">' + tplReplaced + '</div>';
},
onOptionAdd: (value) => {
node.dispatchEvent(new CustomEvent('create', {detail: {'value': value}}));
},
};
const rendererType = (node.dataset['renderer'] !== undefined) ? node.dataset['renderer'] : 'default';
options.render = {...render, ...this.getRenderer(rendererType)};
if (node.dataset['create'] !== undefined) {
options = {...options, ...{
persist: true,
@@ -112,38 +114,6 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
}};
}
if (node.dataset['renderer'] !== undefined && node.dataset['renderer'] === 'color') {
options.render = {...render, ...{
option: function(data, escape) {
let color = data.value;
if (data.color !== undefined) {
color = data.color;
}
return '<div class="list-group-item border-0 p-1 ps-2 text-nowrap"><span style="background-color:' + color + '" class="color-choice-item">&nbsp;</span>' + escape(data.text) + '</div>';
},
item: function(data, escape) {
let color = data.value;
if (data.color !== undefined) {
color = data.color;
}
return '<div class="text-nowrap"><span style="background-color:' + color + '" class="color-choice-item">&nbsp;</span>' + escape(data.text) + '</div>';
}
}};
} else {
options.render = {...render, ...{
// the empty entry would collapse and only show as a tiny 5px line if there is no content inside
option: function(data, escape) {
let text = data.text;
if (text === null || text.trim() === '') {
text = '&nbsp;';
} else {
text = escape(text);
}
return '<div>' + text + '</div>';
}
}};
}
const select = new TomSelect(node, options);
node.addEventListener('data-reloaded', (event) => {
select.clear(true);
@@ -266,8 +236,13 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
options.push(optGroup);
}
// log the one with a group name first (e.g. non-global activities)
options.forEach(child => node.appendChild(child));
emptyOpts.forEach(child => node.appendChild(child));
// append the ones with no parent at the end (e.g. global activities)
const optGroupEmpty = this._createOptgroup('');
emptyOpts.forEach(child => optGroupEmpty.appendChild(child));
node.appendChild(optGroupEmpty)
// if available, re-select the previous selected option (mostly usable for global activities)
node.value = selectedValue;
@@ -278,7 +253,7 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
const optionLength = allOptions.length;
let selectOption = '';
if (optionLength === 1) {
if (optionLength === 1 && node.dataset['autoselect'] === undefined) {
selectOption = allOptions[0].value;
} else if (optionLength === 2 && emptyOption !== null) {
selectOption = allOptions[1].value;
@@ -336,7 +311,13 @@ export default class KimaiFormSelect extends KimaiFormPlugin {
--end;
}
return (start > 0 || end < title.length) ? title.substring(start, end) : title;
let result = (start > 0 || end < title.length) ? title.substring(start, end) : title;
if (result === '' && entity['name'] !== undefined) {
return entity['name'];
}
return result;
}
/**

View File

@@ -0,0 +1,80 @@
/*
* 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.
*/
/*!
* [KIMAI] KimaiFormPlugin: base class for all none ID plugin that handle forms
*/
import KimaiFormPlugin from './KimaiFormPlugin';
export default class KimaiFormTomselectPlugin extends KimaiFormPlugin {
/**
* @param {string} rendererType
* @return array
*/
getRenderer(rendererType)
{
// default renderer
let render = {
option_create: (data, escape) => {
const name = escape(data.input);
if (name.length < 3) {
return null;
}
const tpl = this.translate('select.search.create');
const tplReplaced = tpl.replace('%input%', '<strong>' + name + '</strong>')
return '<div class="create">' + tplReplaced + '</div>';
},
no_results: (data, escape) => {
const tpl = this.translate('select.search.notfound');
const tplReplaced = tpl.replace('%input%', '<strong>' + escape(data.input) + '</strong>')
return '<div class="no-results">' + tplReplaced + '</div>';
},
};
if (rendererType === 'color') {
render = {...render, ...{
option: function(data, escape) {
let item = '<div class="list-group-item border-0 p-1 ps-2 text-nowrap">';
// if no color is set, do NOT add an empty placeholder
if (data.color !== undefined) {
item += '<span style="background-color:' + data.color + '" class="color-choice-item me-2">&nbsp;</span>';
}
item += escape(data.text) + '</div>';
return item;
},
item: function(data, escape) {
let item = '<div class="text-nowrap">';
// if no color is set, do NOT add an empty placeholder
if (data.color !== undefined) {
item += '<span style="background-color:' + data.color + '" class="color-choice-item me-2">&nbsp;</span>';
}
item += escape(data.text) + '</div>';
return item;
}
}};
} else {
render = {...render, ...{
// the empty entry would collapse and only show as a tiny 5px line if there is no content inside
option: function(data, escape) {
let text = data.text;
if (text === null || text.trim() === '') {
text = '&nbsp;';
} else {
text = escape(text);
}
return '<div>' + text + '</div>';
}
}};
}
return render;
}
}

View File

@@ -65,6 +65,8 @@ export default class KimaiTeamForm extends KimaiFormPlugin {
*/
_createMember(option)
{
/** @type {KimaiEscape} ESCAPER */
const ESCAPER = this.getPlugin('escape');
const prototype = this._getPrototype();
let counter = prototype.dataset['widgetCounter'] || prototype.childNodes.length;
let newWidget = prototype.dataset['prototype'];
@@ -72,11 +74,11 @@ export default class KimaiTeamForm extends KimaiFormPlugin {
newWidget = newWidget.replace(/__name__/g, counter);
newWidget = newWidget.replace(/#000000/g, KimaiColor.calculateContrastColor(option.dataset.color));
newWidget = newWidget.replace(/__DISPLAY__/g, option.dataset.display);
newWidget = newWidget.replace(/__DISPLAY__/g, ESCAPER.escapeForHtml(option.dataset.display));
newWidget = newWidget.replace(/__COLOR__/g, option.dataset.color);
newWidget = newWidget.replace(/__INITIALS__/g, option.dataset.initials);
newWidget = newWidget.replace(/__TITLE__/g, option.dataset.title);
newWidget = newWidget.replace(/__USERNAME__/g, option.text);
newWidget = newWidget.replace(/__INITIALS__/g, ESCAPER.escapeForHtml(option.dataset.initials));
newWidget = newWidget.replace(/__TITLE__/g, ESCAPER.escapeForHtml(option.dataset.title));
newWidget = newWidget.replace(/__USERNAME__/g, ESCAPER.escapeForHtml(option.text));
prototype.dataset['widgetCounter'] = (++counter).toString();

View File

@@ -147,18 +147,49 @@ export default class KimaiTimesheetForm extends KimaiFormPlugin {
return null;
}
const date = this.getDateUtils().fromFormat(
this._beginDate.value + ' ' + this._beginTime.value,
this._beginDate.dataset['format'] + ' ' + this._beginTime.dataset['format'],
);
let date = this._parseBegin(this._beginTime.dataset['format']);
if (date.invalid) {
return null;
date = this._parseBegin(this._fixTimeFormat(this._beginTime.dataset['format']));
if (date.invalid) {
return null;
}
}
return date;
}
_parseBegin(timeFormat)
{
return this.getDateUtils().fromFormat(
this._beginDate.value + ' ' + this._beginTime.value,
this._beginDate.dataset['format'] + ' ' + timeFormat,
);
}
_parseEnd(endDate, timeFormat)
{
let date = this.getDateUtils().fromFormat(
endDate.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + timeFormat,
);
if (date.invalid) {
date = this.getDateUtils().fromFormat(
endDate.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._fixTimeFormat(timeFormat),
);
}
return date;
}
_fixTimeFormat(format)
{
return format.replace('HH', 'H').replace('hh', 'h');
}
/**
* @returns {DateTime|null}
* @private
@@ -169,17 +200,11 @@ export default class KimaiTimesheetForm extends KimaiFormPlugin {
return null;
}
let date = this.getDateUtils().fromFormat(
DateTime.now().toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._endTime.dataset['format'],
);
let date = this._parseEnd(DateTime.now(), this._endTime.dataset['format']);
const begin = this._getBegin();
if (begin !== null) {
date = this.getDateUtils().fromFormat(
begin.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._endTime.dataset['format'],
);
date = this._parseEnd(begin, this._endTime.dataset['format']);
if (date < begin) {
date = date.plus({days: 1});
@@ -293,7 +318,7 @@ export default class KimaiTimesheetForm extends KimaiFormPlugin {
this._applyDateToField(newBegin.plus({seconds: seconds}), null, this._endTime);
} else if (begin === null && end !== null) {
this._applyDateToField(end.minus({seconds: seconds}), this._beginDate, this._beginTime);
} else if (begin !== null && seconds > 0) {
} else if (begin !== null && seconds >= 0) {
this._applyDateToField(begin.plus({seconds: seconds}), null, this._endTime);
}
}

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

@@ -85,20 +85,20 @@ export default class KimaiAPILink extends KimaiPlugin {
API.handleError(message, error);
};
let data = {};
if (attributes['payload'] !== undefined) {
data = attributes['payload'];
}
if (method === 'PATCH') {
let data = {};
if (attributes['payload'] !== undefined) {
data = attributes['payload'];
}
API.patch(url, data, successHandle, errorHandle);
} else if (method === 'POST') {
let data = {};
if (attributes['payload'] !== undefined) {
data = attributes['payload'];
}
API.post(url, data, successHandle, errorHandle);
} else if (method === 'DELETE') {
API.delete(url, successHandle, errorHandle);
} else if (method === 'GET') {
API.get(url, data, successHandle, errorHandle);
}
}

View File

@@ -18,6 +18,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
super();
this._selector = '.ticktac-menu';
this._selectorEmpty = '.ticktac-menu-empty';
this._favIconUrl = null;
}
/**
@@ -52,8 +53,6 @@ export default class KimaiActiveRecords extends KimaiPlugin {
// handle duration in the visible UI
this._updateBrowserTitle = !!this.getConfiguration('updateBrowserTitle');
// deactivated direct duration update, becuase it is unclear
// this._updateDuration();
const handle = () => {
this._updateDuration();
};
@@ -77,6 +76,10 @@ export default class KimaiActiveRecords extends KimaiPlugin {
// needs to search in document, to find all running entries, both in "ticktac" and listing pages
const activeRecords = document.querySelectorAll('[data-since]:not([data-since=""])');
if (this._updateBrowserTitle) {
this._changeFavicon(activeRecords.length > 0);
}
if (activeRecords.length === 0) {
if (this._updateBrowserTitle) {
if (document.body.dataset['title'] === undefined) {
@@ -112,7 +115,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
}
/**
* Adapts the ticktac menus accordingg to the given entries (amount and duration).
* Adapts the ticktac menus according to the given entries (amount and duration).
* Does not influence listing pages, as those refresh themselves.
*
* @param {array} entries
@@ -168,7 +171,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
for (let link of allReplacer) {
const replacerName = link.dataset['replacer'];
if (replacerName === 'url') {
link.href = node.dataset['href'].replace('000', timesheet.id);
link.dataset['href'] = node.dataset['href'].replace('000', timesheet.id);
} else if (replacerName === 'activity') {
link.innerText = timesheet.activity.name;
} else if (replacerName === 'project') {
@@ -195,4 +198,36 @@ export default class KimaiActiveRecords extends KimaiPlugin {
});
}
/**
* @param {boolean} running
* @private
*/
_changeFavicon(running)
{
const canvas = document.createElement('canvas');
const orig = document.getElementById('favicon');
if (this._favIconUrl === null) {
this._favIconUrl = orig.href;
}
const link = orig.cloneNode(true);
if (canvas.getContext && link) {
const ratio = window.devicePixelRatio;
const img = document.createElement('img');
canvas.height = canvas.width = 16 * ratio;
img.onload = function () {
const ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
if (running) {
const width = 5.5 * ratio;
ctx.fillStyle = 'rgb(182,57,57)';
ctx.fillRect((canvas.width / 2) - (width / 2), (canvas.height / 2) - (width / 2), width, width);
}
link.href = canvas.toDataURL('image/png');
orig.remove();
document.head.appendChild(link);
};
img.src = this._favIconUrl;
}
}
}

View File

@@ -17,9 +17,10 @@ import { Modal } from 'bootstrap';
export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
constructor(selector) {
constructor(selector, stopSelector) {
super();
this._selector = selector;
this._stopSelector = stopSelector;
}
getId()
@@ -63,7 +64,7 @@ export default class KimaiAjaxModalForm extends KimaiReducedClickHandler {
this.addClickHandler(this._selector, (href) => {
this.openUrlInModal(href);
});
}, this._stopSelector);
}
_getModal()

View File

@@ -52,7 +52,7 @@ export default class KimaiAlert extends KimaiPlugin {
}
const html = `
<div class="modal modal-blur fade" id="` + id + `" tabindex="-1" role="dialog">
<div class="modal" id="` + id + `" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + this._mapClass('danger') + `"></div>
@@ -128,7 +128,7 @@ export default class KimaiAlert extends KimaiPlugin {
}
const html = `
<div class="modal modal-blur fade" tabindex="-1" role="dialog">
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + this._mapClass(type) + `"></div>
@@ -194,7 +194,7 @@ export default class KimaiAlert extends KimaiPlugin {
<div class="toast-body">
` + icon + ' ' + message + `
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="` + translation.get('close') + `"></button>
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="` + translation.get('close') + `"></button>
</div>
</div>`;
@@ -227,7 +227,7 @@ export default class KimaiAlert extends KimaiPlugin {
const css = this._mapClass('info');
const html = `
<div class="modal modal-blur fade" tabindex="-1" role="dialog" data-bs-backdrop="static">
<div class="modal fade" tabindex="-1" role="dialog" data-bs-backdrop="static">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-` + css + `"></div>

View File

@@ -24,7 +24,7 @@ export default class KimaiAlternativeLinks extends KimaiReducedClickHandler {
init() {
this.addClickHandler(this._selector, function(href) {
window.location = href;
});
}, []);
}
}

View File

@@ -227,8 +227,6 @@ export default class KimaiDateUtils extends KimaiPlugin {
}
/**
* TODO remove seconds
*
* @param {int} hours
* @param {int} minutes
* @return {string}
@@ -297,6 +295,11 @@ export default class KimaiDateUtils extends KimaiPlugin {
return new Duration({seconds: 0});
}
// actually, the parsing above should be improved, but that works as well
if (duration[0] === '-' && luxonDuration.valueOf() > 0) {
return luxonDuration.negate();
}
return luxonDuration;
}

View File

@@ -15,10 +15,11 @@ export default class KimaiReducedClickHandler extends KimaiPlugin {
/**
* No _underscore naming for now, as it would be mangled otherwise
* @param selector
* @param callback
* @param {string} selector
* @param {callback} callback
* @param {array<string>} stopSelector
*/
addClickHandler(selector, callback) {
addClickHandler(selector, callback, stopSelector) {
document.body.addEventListener('click', (event) => {
// event.currentTarget is ALWAYS the body
@@ -38,6 +39,12 @@ export default class KimaiReducedClickHandler extends KimaiPlugin {
return;
}
for (let x of stopSelector) {
if (target.matches(x)) {
return;
}
}
target = target.parentNode;
}
@@ -54,6 +61,12 @@ export default class KimaiReducedClickHandler extends KimaiPlugin {
return;
}
for (let x of stopSelector) {
if (target.matches(x)) {
return;
}
}
event.preventDefault();
event.stopPropagation();

View File

@@ -9,7 +9,7 @@
* [KIMAI] KimaiThemeInitializer: initialize theme functionality
*/
import { Tooltip } from 'bootstrap';
import { Tooltip, Offcanvas } from 'bootstrap';
import KimaiPlugin from '../KimaiPlugin';
export default class KimaiThemeInitializer extends KimaiPlugin {
@@ -21,6 +21,10 @@ export default class KimaiThemeInitializer extends KimaiPlugin {
return new Tooltip(tooltipTriggerEl);
});
// support for offcanvas elements
const offcanvasElementList = document.querySelectorAll('.offcanvas');
[...offcanvasElementList].map(offcanvasEl => new Offcanvas(offcanvasEl));
// activate all form plugins
/** @type {KimaiForm} FORMS */
const FORMS = this.getContainer().getPlugin('form');

View File

@@ -163,7 +163,12 @@ export default class KimaiToolbar extends KimaiPlugin {
event.preventDefault();
event.stopPropagation();
let urlParts = target.href.split('/');
pager.value = urlParts[urlParts.length-1];
let pageNumber = urlParts[urlParts.length - 1];
// page number usually is the default value and is therefor missing from the URL
if (!/\d/.test(pageNumber)) {
pageNumber = 1;
}
pager.value = pageNumber;
pager.dispatchEvent(new Event('change'));
document.dispatchEvent(new Event('pagination-change'));
return false;

View File

@@ -0,0 +1,52 @@
/*
* 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.
*/
/*!
* [KIMAI] KimaiUser: information about the current user
*/
import KimaiPlugin from "../KimaiPlugin";
export default class KimaiUser extends KimaiPlugin {
getId() {
return 'user';
}
init() {
this.user = this.getConfigurations().get('user');
}
/**
* @returns {string}
*/
getUserId() {
return this.user.id;
}
/**
* @returns {string}
*/
getName() {
return this.user.name;
}
/**
* @returns {boolean}
*/
isAdmin() {
return this.user.admin;
}
/**
* @returns {boolean}
*/
isSuperAdmin() {
return this.user.superAdmin;
}
}

View File

@@ -109,12 +109,11 @@ export default class KimaiCalendar {
nextYear: this.options['icons']['nextYear'],
};
BootstrapTheme.prototype.rtlIconClasses = {
prev: this.options['icons']['next'],
next: this.options['icons']['previous'],
prevYear: this.options['icons']['nextYear'],
nextYear: this.options['icons']['previousYear'],
prev: this.options['icons']['previous'],
next: this.options['icons']['next'],
prevYear: this.options['icons']['previousYear'],
nextYear: this.options['icons']['nextYear'],
};
let calendarOptions = {
locales: [ enGbLocale, enUsLocale, arLocale, csLocale, daLocale, deLocale, deAtLocale, elLocale,
esLocale, euLocale, faLocale, fiLocale, frLocale, heLocale, hrLocale, huLocale, itLocale, jaLocale, koLocale,
@@ -220,15 +219,23 @@ export default class KimaiCalendar {
}
const element = mouseEnterInfo.el;
let popover = Popover.getInstance(element);
const popoverTitle = DATES.getFormattedDate(event.start) + ' | ' + DATES.formatTime(event.start) + ' - ' + (event.end ? DATES.formatTime(event.end) : '');
const popoverContent = this.renderEventPopoverContent(event);
if (popover === null) {
let popover = Popover.getInstance(element);
if (popover !== null) {
// see https://github.com/kimai/kimai/issues/4043
popover.setContent({
'.popover-header': popoverTitle,
'.popover-body': popoverContent
});
} else {
// https://getbootstrap.com/docs/5.0/components/popovers/#options
popover = new Popover(element, {
title: DATES.getFormattedDate(event.start) + ' | ' + DATES.formatTime(event.start) + ' - ' + (event.end ? DATES.formatTime(event.end) : ''),
title: popoverTitle,
placement: 'top',
html: true,
content: this.renderEventPopoverContent(event),
content: popoverContent,
trigger: 'focus',
});
}
@@ -432,8 +439,14 @@ export default class KimaiCalendar {
calendarSource = {...calendarSource, ...{
id: 'kimai-' + source.id,
events: (fetchInfo, successCallback, failureCallback) => {
let url = source.url.replace('{from}', DATES.formatForAPI(fetchInfo.start));
url = url.replace('{to}', DATES.formatForAPI(fetchInfo.end));
const targetFrom = DATES.formatForAPI(fetchInfo.start);
const targetTo = DATES.formatForAPI(fetchInfo.end);
let url = source.url;
url = url.replace('{from}', targetFrom);
url = url.replace('__FROM__', targetFrom);
url = url.replace('{to}', targetTo);
url = url.replace('__TO__', targetTo);
API.get(url, {}, result => {
let apiEvents = [];
@@ -450,6 +463,29 @@ export default class KimaiCalendar {
name: 'google',
editable: false,
}};
} else if (source.type === 'json') {
calendarSource = {...calendarSource, ...{
id: 'json-' + source.id,
editable: false,
events: (fetchInfo, successCallback, failureCallback) => {
const targetFrom = DATES.formatForAPI(fetchInfo.start);
const targetTo = DATES.formatForAPI(fetchInfo.end);
let url = source.url;
url = url.replace('{from}', targetFrom);
url = url.replace('__FROM__', targetFrom);
url = url.replace('{to}', targetTo);
url = url.replace('__TO__', targetTo);
API.get(url, {}, result => {
let apiEvents = [];
for (const record of result) {
apiEvents.push(record);
}
successCallback(apiEvents);
}, failureCallback);
},
}};
} else if (source.type === 'ical') {
calendarSource = {...calendarSource, ...{
id: 'ical-' + source.id,
@@ -536,12 +572,22 @@ export default class KimaiCalendar {
color = defaultColor;
}
/** @type {KimaiDateUtils} DATES */
const DATES = this.kimai.getPlugin('date');
let title = this.options['patterns']['title'];
title = title.replace('{project}', apiItem.project.name);
title = title.replace('{customer}', apiItem.project.customer.name);
title = title.replace('{description}', apiItem.description ?? '');
title = title.replace('{activity}', apiItem.activity.name ?? '');
if (apiItem.end === null) {
// duration = 0 and end = null => is a running entry
title = title.replace('{duration}', '');
} else {
title = title.replace('{duration}', DATES.formatDuration(apiItem.duration));
}
if (title === '' || title === null) {
title = apiItem.activity.name;
}
@@ -573,6 +619,13 @@ export default class KimaiCalendar {
/** @type {KimaiEscape} escaper */
const escaper = this.kimai.getPlugin('escape');
let tags = '';
if (eventObj.tags !== null && eventObj.tags.length > 0) {
for (let tag of eventObj.tags) {
tags += '<span class="badge bg-green">' + escaper.escapeForHtml(tag) + '</span>';
}
}
return `
<div class="calendar-entry">
<ul>
@@ -581,8 +634,7 @@ export default class KimaiCalendar {
<li>` + this.options['translations']['activity'] + `: ` + escaper.escapeForHtml(eventObj.activity) + `</li>
</ul>` +
(eventObj.description !== null || eventObj.tags.length > 0 ? '<hr>' : '') +
(eventObj.description ? '<p>' + eventObj.description + '</p>' : '') +
(eventObj.tags !== null && eventObj.tags.length > 0 ? '<span class="badge bg-green">' + eventObj.tags.join('</span> <span class="badge bg-green">') + '</span>' : '') + `
(eventObj.description ? '<div>' + escaper.escapeForHtml(eventObj.description) + '</div>' : '') + tags + `
</div>`;
}

View File

@@ -70,13 +70,19 @@ export default class KimaiContextMenu {
{
const dropdownElement = this.getContextMenuElement();
dropdownElement.style.zIndex = '1021'; // stay on top of sticky elements (like table header)
if (!dropdownElement.classList.contains('action-dropdown')) {
dropdownElement.classList.add('action-dropdown');
}
dropdownElement.innerHTML = html;
dropdownElement.style.position = 'fixed';
dropdownElement.style.top = (event.clientY) + 'px';
dropdownElement.style.left = (event.clientX) + 'px';
const dropdownListener = () => {
const dropdownListener = (event) => {
if (event.target.classList.contains('dropdown-toggle') || event.target.classList.contains('dropdown-divider')) {
return;
}
dropdownElement.classList.remove('d-block');
if (!dropdownElement.classList.contains('d-none')) {
dropdownElement.classList.add('d-none');

45
assets/sass/_app-rtl.scss Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
$modal-backdrop-opacity: 0.6 !default;
/*
THIS DOES NOT WORK AS EXPECTED, AS TABLER IS NOT REGENERATED HERE.
SO WE CANNOT CHANGE VARIABLES, LIKE THE ABOVE...
*/
@import '~@tabler/core/dist/css/tabler.rtl.css';
@import '~@tabler/core/dist/css/tabler-vendors.rtl.css';
/**
* Everyone needs icons
*/
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts/";
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';
/**
* We need that, to compile the rest of the file
*/
@import "bootstrap/scss/functions";
@import "@tabler/core/src/scss/variables";
@import "@tabler/core/src/scss/variables-dark";
@import "@tabler/core/src/scss/mixins";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
/**
* Kimai related stuff
*/
@import "kimai";
@import "rtl";

29
assets/sass/_app.scss Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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.
*/
$modal-backdrop-opacity: 0.6 !default;
@import '~@tabler/core/src/scss/tabler';
@import '~@tabler/core/src/scss/vendor/litepicker';
@import '~@tabler/core/src/scss/vendor/tom-select';
/**
* Everyone needs icons
*/
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts/";
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/brands';
/**
* Kimai specific additions
*/
@import "kimai";

View File

@@ -34,10 +34,10 @@ p {
.text-center {
text-align: center;
}
.text-left {
.text-left, .text-begin {
text-align: left;
}
.text-right {
.text-right, .text-end {
text-align: right;
}
.text-nowrap {

View File

@@ -7,15 +7,17 @@
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/tables";
@import "bootstrap/scss/list-group";
@import "bootstrap/scss/card";
@import "bootstrap/scss/utilities";
body {
font-family: $font-family-sans-serif;
@@ -80,7 +82,6 @@ body {
font-size: 20px;
> small {
color: #666;
display: block;
margin-top: 5px;
}
@@ -107,6 +108,13 @@ body {
text-align: right;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.invoice-items {
.table {
thead th {

18
assets/sass/_kimai.scss Normal file
View File

@@ -0,0 +1,18 @@
@import "layout";
@import "error-page";
@import "print";
@import "content";
@import "loading-spinner";
@import "tables";
@import "calendar";
@import "ticktac";
@import "selectpicker";
@import "forms";
@import "modal";
@import "progressbar";
@import "avatar";
@import "theme-dark";
@import "pages";
@import "tabler-fixes";
@import "help";
@import "rtl";

View File

@@ -1,27 +0,0 @@
/*
* 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.
*/
@import 'variables';
@import 'layout';
@import 'error-page';
@import 'print';
@import 'content';
@import 'loading-spinner';
@import 'tables';
@import 'calendar';
@import 'ticktac';
@import 'sweetalert';
@import 'selectpicker';
@import 'forms';
@import 'modal';
@import 'progressbar';
@import 'avatar';
@import 'theme-dark';
@import 'pages';
@import 'tabler-fixes';
@import 'help';
@import 'rtl';

View File

@@ -3,18 +3,18 @@ $avatar-base-size: 30;
.initials {
font-weight: bold;
font-size: ceil($avatar-base-size / 2 - 2)+px;
font-size: ceil(calc($avatar-base-size / 2 - 2))+px;
}
$avatarSizes: "xs" .75, "sm" 1.25, "md" 1.5, "lg" 2;
@each $avatarSizeName, $avatarBaseSize in $avatarSizes {
.avatar-#{$avatarSizeName} {
width: ceil($avatar-base-size * $avatarBaseSize)+px;
height: ceil($avatar-base-size * $avatarBaseSize)+px;
width: ceil(calc($avatar-base-size * $avatarBaseSize))+px;
height: ceil(calc($avatar-base-size * $avatarBaseSize))+px;
.initials {
font-size: ceil($avatar-base-size * $avatarBaseSize / 2 - 2)+px;
font-size: ceil(calc($avatar-base-size * $avatarBaseSize / 2 - 2))+px;
}
}
}
@@ -23,10 +23,10 @@ $avatarSizes: "xs" .75, "sm" 1.25, "md" 1.5, "lg" 2;
border-radius: 50%;
border: 3px solid #fff;
.avatar {
width: ceil($avatar-base-size * 2.75)+px;
height: ceil($avatar-base-size * 2.75)+px;
width: ceil(calc($avatar-base-size * 2.75))+px;
height: ceil(calc($avatar-base-size * 2.75))+px;
.initials {
font-size: ceil($avatar-base-size * 2.75 / 2 - 2)+px;
font-size: ceil(calc($avatar-base-size * 2.75 / 2 - 2))+px;
}
}
}
@@ -39,3 +39,8 @@ table.dataTable.table > tbody > tr > td {
}
}
}
/* decreases the margin between avatars, see https://github.com/tabler/tabler/issues/1567 */
.avatar-list-stacked .avatar {
margin-right: calc(var(--tblr-avatar-size)*-.2)!important;
}

View File

@@ -3,6 +3,9 @@
padding: 0;
list-style-type: none;
}
div {
white-space: pre-line;
}
}
.draggable {
@@ -13,3 +16,5 @@
--bs-gray-400: var(--tblr-border-color);
--bs-gray-200: var(--tblr-gray-200);
}
.fc-day-sat, .fc-day-sun { background-color: var(--tblr-bg-surface-secondary); }

View File

@@ -5,6 +5,11 @@
* file that was distributed with this source code.
*/
/* used in security screens and other full-size pages */
.page-center {
justify-content: center;
}
/* make sure that elements can be hidden without taking space (eg. hidden modals like the search or column visibility) */
.hidden-no-space {
margin: 0;
@@ -33,11 +38,6 @@ td {
}
}
.label-gray {
background-color: $gray-lte;
color: #666;
}
.open-edit {
cursor: pointer;
}
@@ -79,15 +79,6 @@ table.dataTable thead > tr > th.hw-min {
max-height: 340px;
}
.card {
.card-tools {
/* a button that is directly connected with a pagination element inside the box tools (eg. project list on customer detail page) */
.btn-pager {
float: left;
margin-right: 5px;
}
}
}
#customer_details_box,
#project_details_box,
#activity_details_box {

View File

@@ -1,19 +0,0 @@
/*
* 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.
*/
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts/";
@import "@fortawesome/fontawesome-free/scss/fontawesome";
@import "@fortawesome/fontawesome-free/scss/regular";
@import "@fortawesome/fontawesome-free/scss/solid";
@import "@fortawesome/fontawesome-free/scss/brands";
/* all icon-buttons with fontawesome icons */
.btn-icon i.icon {
font-size: 16px;
color: $text-muted;
padding-top: 2px;
}

View File

@@ -26,6 +26,9 @@
margin-bottom: 0;
}
}
.input-group {
width: unset;
}
}
}
@@ -33,6 +36,23 @@
width: 20px;
height: 20px;
display: inline-block;
margin-right: 10px;
border-radius: var(--tblr-border-radius);
}
/* e.g. the work contract settings is user profile render rows with mb-3 and the last row doesn't need that */
fieldset > .mb-3.row:last-child {
margin-bottom: 0!important;
}
.form-fieldset-light {
border-radius: 0;
margin-bottom: 0;
border-top: none;
border-right: none;
border-left: none;
background-color: unset;
}
.form-fieldset-light:last-child {
border:none;
}

View File

@@ -1,9 +1,5 @@
.inline-search {
max-width: 200px;
/* the entire inline-search should actually use .input-group-flat, but that causes some weird css problems inside the dropdown menu */
#searchTerm {
border-right: 0;
}
}
@media (min-width: 360px) {
@@ -38,3 +34,26 @@ h1.navbar-brand a {
/* bootstrap thead.sticky-top has z-index 1020 and the reporting form dropdowns hide behind that */
z-index: 1021;
}
/* reduce the default font size for the brand header */
.navbar {
--tblr-navbar-brand-font-size: 1rem;
}
/* user shortcuts dropdown */
.user-shortcuts {
.dropdown-menu-card {
min-width: 260px;
}
.user-shortcuts-icon {
background-color: var(--tblr-bg-surface-secondary);
color: var(--tblr-gray-500);
height: 3.125rem;
width: 3.125rem;
margin-left: auto;
margin-right: auto;
display: flex;
align-items: center;
justify-content: center;
}
}

View File

@@ -11,7 +11,7 @@
left: 0;
width: 100%;
height: 100%;
z-index: 50;
z-index: 1021;
background: rgba(255, 255, 255, 0.7);
> .fas {
position: absolute;

View File

@@ -1,26 +1,21 @@
@import "tom-select/dist/scss/tom-select.bootstrap5";
/* bootstrap thead.sticky-top has z-index 1020 and tomselect dropdowns often hide behind that */
.ts-dropdown {
z-index: 1021;
}
/* Tabler defines a min-width of 7rem, what makes many input fields become a two-line field
e.g. a 7 rem input does not fit behind a word like "Germany" in a 3 column form inside a modal */
.ts-control {
> input {
min-width: unset;
}
.item {
white-space: nowrap!important;
}
}
.ts-dropdown {
.optgroup-header {
background-color: #eee;
color: #000;
font-weight: 600;
}
[data-selectable].option {
padding-left: 20px;
.optgroup {
[data-selectable].option {
padding-left: 20px;
}
}
}

View File

@@ -1,16 +0,0 @@
.swal2-popup {
font-size: unset;
}
body.swal2-toast-shown .swal2-container {
// never block the top two bars double-bars display (smaller displays)
@media only screen and (max-width: 768px) {
top: 95px !important;
width: 80%;
}
// never block the top bar on single-bar display (larger devices)
@media only screen and (min-width: 768px) {
top: 60px !important;
}
}

View File

@@ -1,6 +1,51 @@
@import "@tabler/core/src/scss/variables";
/* fix for vertical labels in date-time pickers, if they are used in half-column forms, e.g. "create tasks" or "create expenses" */
fieldset legend.col-form-label {
padding-top: 0;
}
/* See project assignment to teams */
fieldset.form-fieldset > legend {
font-size: 1rem;
font-weight: bold;
}
/* Fixing the margin between the divider and items in context menu or dropdowns with optgroups */
.ts-dropdown .optgroup:before {
--tblr-spacer: .5rem;
}
.dropdown-divider {
--tblr-dropdown-divider-margin-y: .5rem;
}
/* fix translucent scroll border (e.g. timesheet modal duration dropdown) - see https://github.com/tabler/tabler/issues/1606 */
.dropdown-menu {
background-clip: border-box;
}
/* hide empty fieldset - see https://github.com/tabler/tabler/issues/1650 */
fieldset:empty {
display: none;
}
:host,:root,[data-bs-theme=light] {
/* remove the shadow from all form element groups */
--tblr-box-shadow-input: none;
}
.navbar[data-bs-theme=dark] {
/* give navigation elements slightly higher contrast */
--tblr-navbar-color: hsla(0,0%,100%,.8);
}
/* this is not a bugfix, but it adds a border for better visual segregation */
.nav-pills .nav-link.active {
border-width: 1px;
border-style: solid;
}
[data-bs-theme=dark] {
/* fixes https://github.com/tabler/tabler/issues/1974 */
.litepicker .container__days .day-item.is-in-range {
--litepicker-is-in-range-color: var(--tblr-primary-text-emphasis);
}
}

View File

@@ -4,7 +4,6 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
@import "variables";
table.dataTable {
clear: both;
@@ -27,7 +26,7 @@ table.dataTable {
thead .sorting_asc:after,
thead .sorting_desc:after {
padding-left: 5px;
font-family: 'Font Awesome 5 Free';
font-family: 'Font Awesome 6 Free';
opacity: 0.5;
font-size: 12px;
}
@@ -93,7 +92,7 @@ table.dataTable {
&.summary td {
font-weight: bold;
border: 0;
background-color: var(--tblr-table-striped-bg);
background-color: var(--tblr-bg-surface-secondary);
}
th.multiCheckbox {
width: 15px;
@@ -118,30 +117,17 @@ table.dataTable {
padding: .3em .6em .3em;
line-height: 24px;
}
span.label-activity,
span.label-project,
span.label-customer {
a {
color: unset;
padding-bottom: 2px;
border-bottom: 1px dotted $gray-lte;
&:hover {
border-bottom: 1px dotted darken($gray-lte, 20);
}
}
}
span.label-invisible {
opacity: 0.8;
opacity: 0.6;
}
}
th.weekend,
td.weekend {
background-color: #f9f9f9;
background-color: var(--tblr-bg-surface-tertiary);
}
/* order is important, "today” should overwrite "weekend" therefor later in the file */
th.today,
td.today {
background-color: $highlight-today;
th.today {
background-color: var(--tblr-highlight-bg);
}
th.total,
td.total {
@@ -167,3 +153,10 @@ table.table-hover {
}
}
}
/* For the context menu */
.action-dropdown,
.actions .dropdown .dropdown-menu {
// stay on top of sticky elements (like table header)
z-index: 1021;
}

View File

@@ -1,48 +1,22 @@
@include dark-mode {
.form-check-input {
border-color: $input-border-color;
}
/* selectpicker.scss / Tom Select */
.ts-wrapper.form-select .ts-control,
.ts-wrapper.form-select.single.input-active .ts-control {
color: $dark-mode-text;
}
.ts-dropdown {
background-color: $dark-mode-lighten;
color: $dark-mode-text;
}
.ts-control {
> input {
min-width: unset;
color: $dark-mode-text;
}
@include color-mode(dark, true) {
$dark-font-opacity: 0.6;
.item {
background-color: $dark;
color: $dark-mode-text;
}
}
.optgroup-header {
background-color: $dropdown-dark-bg;
color: $dark-mode-text;
}
/*
--tblr-body-bg: #1e222b;
--tblr-bg-surface-tertiary: #1e222b;
--tblr-bg-surface: #1e222b;
--tblr-bg-surface-secondary: #17202b;
//--tblr-muted: #d9dcdf;
*/
.table thead th {
color: inherit;
opacity: $dark-font-opacity;
}
table.dataTable {
th.weekend, td.weekend {
background-color: $dark-mode-weekend;
color: $dark-mode-text;
}
/* must be defined after weekend, to overwrite it */
th.today, td.today {
background-color: $dark-mode-today;
color: $dark-mode-text;
}
tr {
&.summary td {
background-color: $dark-mode-darken;
}
thead .sorting:after {
opacity: $dark-font-opacity;
}
}
@@ -50,7 +24,19 @@
background: rgba(0, 0, 0, 0.5);
> .fas {
color: $dark-mode-text;
color: var(--tblr-white);
}
}
/* Fix tabs pills (e.g. user profile) */
.nav {
--tblr-nav-link-color: inherit;
opacity: $dark-font-opacity;
}
.datagrid-title {
color: inherit;
opacity: $dark-font-opacity;
}
.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
color: inherit;
}
}

View File

@@ -37,8 +37,6 @@
@include media-breakpoint-down(lg) {
aside.navbar .btn-outline-white,
header.navbar .btn-outline-white {
background-color: var(--tblr-body-color);
border-color: hsla(0,0%,100%,.2);
color: hsla(0,0%,100%,.7);
}
}

View File

@@ -1,30 +0,0 @@
/*
* 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.
*/
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";
@import "@tabler/core/src/scss/variables";
@import "@tabler/core/src/scss/mixins";
/* For highlighting rows, fieldsets and so on */
$highlight-bg: #f5f5f5;
$highlight-today: #fcf8e3;
$red: #dd4b39;
$green: #00a65a;
$yellow: #f0ad4e;
$blue: #0073b7;
$gray-lte: #d2d6de;
$kimai-default: $gray-lte;
$box-border-radius: 3px;
$dark-mode-today: var(--tblr-blue);
$dark-mode-weekend: lighten($dark, 5%) !default;

View File

@@ -14,7 +14,7 @@
}
],
"require": {
"php": "8.1.*||8.2.*",
"php": "8.1.*||8.2.*||8.3.*",
"ext-gd": "*",
"ext-intl": "*",
"ext-json": "*",
@@ -24,28 +24,28 @@
"ext-xml": "*",
"ext-xsl": "*",
"ext-zip": "*",
"composer/package-versions-deprecated": "^1.8",
"composer-runtime-api": "^2.0",
"azuyalabs/yasumi": "^2.6",
"composer/semver": "^3.3",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.8",
"endroid/qr-code": "^4.4.9",
"endroid/qr-code": "^4.8",
"erusev/parsedown": "^1.6",
"friendsofsymfony/rest-bundle": "^3.0",
"gedmo/doctrine-extensions": "^3.6",
"jeroendesloovere/vcard": "^1.7",
"jms/serializer-bundle": "^5.0",
"kevinpapst/tabler-bundle": "^0.10",
"kevinpapst/tabler-bundle": "^1.4",
"league/csv": "^9.4",
"mpdf/mpdf": "^8.0",
"nelmio/api-doc-bundle": "^4.0",
"nelmio/cors-bundle": "^2.0",
"onelogin/php-saml": "^4.0",
"pagerfanta/pagerfanta": "^3.0",
"phpoffice/phpspreadsheet": "^1.16",
"phpoffice/phpspreadsheet": "^2.0",
"phpoffice/phpword": "^1.0",
"psr/container": "^1.0||^2.0",
"psr/log": "^2.0||^3.0",
"psr/container": "^2.0",
"psr/log": "^3.0",
"scheb/2fa-backup-code": "^6.2",
"scheb/2fa-bundle": "^6.2",
"scheb/2fa-totp": "^6.2",
@@ -59,6 +59,7 @@
"symfony/http-client": "^6.0",
"symfony/intl": "^6.0",
"symfony/mailer": "^6.0",
"symfony/mime": "^6.0",
"symfony/monolog-bundle": "^3.4",
"symfony/rate-limiter": "^6.0",
"symfony/runtime": "^6.0",
@@ -68,7 +69,7 @@
"symfony/translation": "^6.0",
"symfony/twig-bundle": "^6.0",
"symfony/validator": "^6.0",
"symfony/webpack-encore-bundle": "^1.16",
"symfony/webpack-encore-bundle": "^2.0",
"symfony/yaml": "^6.0",
"twig/cssinliner-extra": "^3.0",
"twig/extra-bundle": "^3.0",
@@ -78,11 +79,12 @@
},
"require-dev": {
"ext-simplexml": "*",
"dama/doctrine-test-bundle": "^7.0",
"dama/doctrine-test-bundle": "^8.0",
"doctrine/doctrine-fixtures-bundle": "^3.2",
"fakerphp/faker": "^1.15",
"friendsofphp/php-cs-fixer": "^3.3",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-doctrine": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
@@ -105,7 +107,6 @@
],
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
"symfony/flex": true,
"symfony/runtime": true
},
@@ -130,6 +131,7 @@
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-intl": "*",
"symfony/polyfill-iconv": "*",
@@ -169,18 +171,23 @@
"@tests-integration"
],
"linting": [
"composer validate --strict",
"bin/console lint:container",
"bin/console lint:yaml config --parse-tags",
"bin/console lint:twig templates --show-deprecations",
"bin/console lint:xliff translations",
"bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction"
"bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction",
"bin/console lint:xliff translations"
],
"tests": "vendor/bin/phpunit tests/",
"tests-unit": "vendor/bin/phpunit --exclude-group integration tests/",
"tests-integration": "vendor/bin/phpunit --group integration tests/",
"phpstan": [
"vendor/bin/phpstan analyse -c phpstan.neon",
"@phpstan-src",
"@phpstan-tests"
],
"phpstan-src": [
"vendor/bin/phpstan analyse -c phpstan.neon"
],
"phpstan-tests": [
"vendor/bin/phpstan analyse -c tests/phpstan.neon"
],
"codestyle": "vendor/bin/php-cs-fixer fix --dry-run --verbose --show-progress=none",
@@ -190,13 +197,10 @@
"symfony/symfony": "*"
},
"extra": {
"branch-alias": {
"dev-main": "2.0.x-dev"
},
"symfony": {
"id": "01C3FWRDJJEX9K6Y3A4XDFXPBR",
"allow-contrib": true,
"require": "6.2.*"
"require": "6.4.*"
}
}
}

5826
composer.lock generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ parameters:
# environment variables are not available yet.
# You should not need to change this value.
env(DATABASE_URL): ''
env(DATABASE_VERSION): ~
doctrine:
dbal:
@@ -15,22 +14,26 @@ doctrine:
#schema_filter: ~^(?!(bundle_migration_|kimai2_sessions))~
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
# If this is wrong, automatic database detection might fail and find false-negatives when running
# doctrine:migrations:diff on null columns with MariaDB.
# This here is mainly a fallback for times, when users have not configured the database version in the URL
server_version: '%env(string:DATABASE_VERSION)%'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
collation: utf8mb4_unicode_ci
schema_manager_factory: doctrine.dbal.default_schema_manager_factory
types:
datetime: App\Doctrine\UTCDateTimeType
datetime_immutable: App\Doctrine\UTCDateTimeImmutableType
orm:
controller_resolver:
# FIXME this is causing a deprecation and needs to be changed
# auto_mapping: false
auto_mapping: true
auto_generate_proxy_classes: '%kernel.debug%'
default_entity_manager: default
enable_lazy_ghost_objects: true
entity_managers:
default:
report_fields_where_declared: true
connection: default
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
@@ -50,7 +53,10 @@ doctrine:
when@test:
doctrine:
dbal:
logging: false
connections:
default:
logging: false
use_savepoints: true
when@prod:
doctrine:

View File

@@ -5,3 +5,4 @@ doctrine_migrations:
table_name: 'migration_versions'
migrations_paths:
'DoctrineMigrations': '%kernel.project_dir%/migrations'
custom_template: '%kernel.project_dir%/migrations/MigrationTemplate.txt'

View File

@@ -1,7 +1,25 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
parameters:
env(TRUSTED_PROXIES): ''
framework:
secret: '%env(APP_SECRET)%'
default_locale: en
csrf_protection: true
annotations: false
handle_all_throwables: true
disallow_search_engine_index: true
set_content_language_from_locale: true
serializer:
enable_attributes: true
trusted_proxies: '%env(string:TRUSTED_PROXIES)%'
exceptions:
App\Validator\ValidationFailedException:
log_level: debug
default_locale: en
http_method_override: false
# Enables session support. Note that the session will ONLY be started if you read or write from it.
@@ -13,8 +31,6 @@ framework:
cookie_httponly: true
storage_factory_id: session.storage.factory.native
#esi: ~
#fragments: ~
php_errors:
log: true
@@ -23,6 +39,7 @@ framework:
validation:
email_validation_mode: html5
enable_attributes: true
when@dev:
framework:

View File

@@ -75,7 +75,7 @@ kimai:
# PERMISSIONS
# --------------------------------------------------------------------------------
permissions:
# mapping complex rule sets of single permissions to named "sets" ("set name" = [array of "permissions and @SETS"])
# mapping a "set name" to an array of "permission names"
sets:
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','time_activity','delete_activity','permissions_activity']
ACTIVITIES_ALL_TEAMLEAD: ['view_teamlead_activity','edit_teamlead_activity','budget_teamlead_activity','time_teamlead_activity','permissions_teamlead_activity']
@@ -95,7 +95,7 @@ kimai:
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet','weekly_own_timesheet']
TIMESHEET_OTHER: ['view_other_timesheet','start_other_timesheet','stop_other_timesheet','create_other_timesheet','edit_other_timesheet','export_other_timesheet','delete_other_timesheet']
PROFILE: ['view_own_profile','edit_own_profile','password_own_profile','preferences_own_profile','api-token_own_profile']
PROFILE_OTHER: ['view_other_profile','edit_other_profile','password_other_profile','roles_other_profile','preferences_other_profile','api-token_other_profile','teams_other_profile']
PROFILE_OTHER: ['view_other_profile','edit_other_profile','password_other_profile','roles_other_profile','preferences_other_profile','api-token_other_profile','teams_other_profile','supervisor_other_profile']
TAGS: ['view_tag','manage_tag','create_tag','delete_tag']
USER: ['view_user','create_user','delete_user','role_permissions']
RATE: ['view_rate_own_timesheet','edit_rate_own_timesheet']
@@ -104,29 +104,23 @@ kimai:
BILLABLE: ['edit_billable_own_timesheet','edit_billable_other_timesheet']
TEAMS: ['view_team','create_team','edit_team','delete_team']
LOCKDOWN: ['lockdown_grace_timesheet','lockdown_override_timesheet']
REPORTING: ['view_reporting','view_other_reporting','project_reporting','customer_reporting']
# some single default definitions for roles
SINGLE_USER: ['view_team_member','time_team_project','create_tag','view_reporting']
SINGLE_TEAMLEAD: ['view_rate_own_timesheet','view_rate_other_timesheet','hourly-rate_own_profile','view_team_member']
SINGLE_ADMIN: ['hourly-rate_own_profile','edit_exported_timesheet','teams_own_profile','view_team_member','view_all_data']
SINGLE_SUPER_ADMIN: ['hourly-rate_own_profile','hourly-rate_other_profile','roles_own_profile','system_information','system_configuration','plugins','edit_exported_timesheet','teams_own_profile','view_team_member','upload_invoice_template','view_all_data']
# link above sets to one complete set for each user role
ROLE_USER: ['@TIMESHEET','@PROFILE','@SINGLE_USER']
ROLE_TEAMLEAD: ['@ACTIVITIES_TEAMLEAD','@PROJECTS_TEAMLEAD','@CUSTOMERS_TEAMLEAD','@TIMESHEET_OTHER','@INVOICE','@TIMESHEET','@PROFILE','@EXPORT','@BILLABLE','@TAGS','@REPORTING','@SINGLE_TEAMLEAD']
ROLE_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@BILLABLE','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_ADMIN']
ROLE_SUPER_ADMIN: ['@ACTIVITIES','@PROJECTS','@CUSTOMERS','@INVOICE','@INVOICE_ADMIN','@TIMESHEET','@TIMESHEET_OTHER','@PROFILE','@PROFILE_OTHER','@USER','@TEAMS','@RATE','@RATE_OTHER','@EXPORT','@BILLABLE','@TAGS','@LOCKDOWN','@REPORTING','@SINGLE_SUPER_ADMIN']
# mapping "sets" or permissions to user roles ("role name" = [array of "set names"])
REPORTING: ['view_reporting','view_other_reporting','activity_reporting','project_reporting','customer_reporting']
EVERYONE: ['api_access','hours_own_profile']
# permissions which are deactivated, as these features are hidden for now
# brave users can try to activate them and be surprised what happens
REGISTER_BETA: []
# mapping a "role name" to an array of "set names"
maps:
ROLE_USER: ['ROLE_USER']
ROLE_TEAMLEAD: ['ROLE_TEAMLEAD']
ROLE_ADMIN: ['ROLE_ADMIN']
ROLE_SUPER_ADMIN: ['ROLE_SUPER_ADMIN']
# add or remove single permissions
ROLE_USER: ['TIMESHEET','PROFILE', 'EVERYONE']
ROLE_TEAMLEAD: ['ACTIVITIES_TEAMLEAD','PROJECTS_TEAMLEAD','CUSTOMERS_TEAMLEAD','TIMESHEET_OTHER','INVOICE','TIMESHEET','PROFILE','EXPORT','BILLABLE','TAGS','REPORTING', 'EVERYONE']
ROLE_ADMIN: ['ACTIVITIES','PROJECTS','CUSTOMERS','INVOICE','INVOICE_ADMIN','TIMESHEET','TIMESHEET_OTHER','PROFILE','TEAMS','RATE','RATE_OTHER','EXPORT','BILLABLE','TAGS','LOCKDOWN','REPORTING', 'EVERYONE']
ROLE_SUPER_ADMIN: ['ACTIVITIES','PROJECTS','CUSTOMERS','INVOICE','INVOICE_ADMIN','TIMESHEET','TIMESHEET_OTHER','PROFILE','PROFILE_OTHER','USER','TEAMS','RATE','RATE_OTHER','EXPORT','BILLABLE','TAGS','LOCKDOWN','REPORTING', 'EVERYONE']
# mapping a "role name" to an array of "permission names"
roles:
ROLE_USER: []
ROLE_TEAMLEAD: []
ROLE_ADMIN: []
ROLE_SUPER_ADMIN: []
ROLE_USER: ['view_team_member','time_team_project','create_tag','view_reporting']
ROLE_TEAMLEAD: ['view_rate_own_timesheet','view_rate_other_timesheet','hourly-rate_own_profile','view_team_member','hours_other_profile']
ROLE_ADMIN: ['hourly-rate_own_profile','edit_exported_timesheet','teams_own_profile','view_team_member','view_all_data','contract_other_profile','hours_other_profile']
ROLE_SUPER_ADMIN: ['hourly-rate_own_profile','hourly-rate_other_profile','roles_own_profile','supervisor_own_profile','system_information','system_configuration','plugins','edit_exported_timesheet','teams_own_profile','view_team_member','upload_invoice_template','view_all_data','contract_other_profile','hours_other_profile']
# --------------------------------------------------------------------------------
@@ -158,14 +152,20 @@ kimai:
# --------------------------------------------------------------------------------
# INVOICES
# --------------------------------------------------------------------------------
# invoice:
# # all files in these directories will be used as invoice documents (if supported by a renderer)
# documents:
# - 'var/invoices/'
# - 'templates/invoice/renderer/'
# invoice:
# # all files in these directories will be used as invoice documents (if supported by a renderer)
# documents:
# - 'var/invoices/'
# - 'templates/invoice/renderer/'
# # allow to upload twig templates as invoice documents
# upload_twig: true
# --------------------------------------------------------------------------------
when@test:
kimai:
data_dir: '%kernel.project_dir%/tests/_data'
permissions:
roles:
ROLE_ADMIN: ['contract_other_profile']
ROLE_SUPER_ADMIN: ['contract_other_profile']

View File

@@ -1,42 +1,58 @@
monolog:
channels: ["deprecation"]
when@prod:
monolog:
channels: ["deprecation"]
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [403, 404]
nested:
handler: file_log
excluded_http_codes:
- {400: ['^/api/']}
- {401: ['^/api/']}
- 403
- 404
- {405: ['/homepage$', '/login_check$', '/export/data$']}
channels: ["!deprecation"]
file_log:
type: stream
level: info
path: "%kernel.logs_dir%/%kernel.environment%.log"
formatter: monolog.formatter.kimai
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
channels: ["deprecation"]
path: "%kernel.logs_dir%/deprecations.log"
channels: ["!event", "!doctrine", "!deprecation"]
when@dev:
monolog:
channels: ["deprecation"]
handlers:
main:
type: fingers_crossed
action_level: notice
handler: file_log
excluded_http_codes:
- {400: ['^/api/']}
- {401: ['^/api/']}
- 403
- 404
- {405: ['/homepage$', '/login_check$', '/export/data$']}
channels: ["!event", "!deprecation"]
file_log:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
channels: ["!event"]
level: debug
formatter: monolog.formatter.kimai
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
channels: ["!event", "!doctrine", "!deprecation"]
deprecation:
type: stream
channels: ["deprecation"]
path: "%kernel.logs_dir%/deprecations.log"
formatter: monolog.formatter.deprecation
when@test:
monolog:
@@ -46,3 +62,4 @@ when@test:
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
channels: ["!event"]
formatter: monolog.formatter.kimai

View File

@@ -40,27 +40,23 @@ nelmio_api_doc:
- { alias: TeamCollection, type: App\Entity\Team, groups: [Default, Collection, Team] }
- { alias: TeamMember, type: App\Entity\TeamMember, groups: [Team_Entity] }
- { alias: TeamMembership, type: App\Entity\TeamMember, groups: [User_Entity] }
- { alias: Invoice, type: App\Entity\Invoice, groups: [Default, Entity, Invoice, Invoice_Entity] }
- { alias: InvoiceCollection, type: App\Entity\Invoice, groups: [Default, Collection, Invoice] }
areas:
path_patterns:
- ^/api(?!/doc)
documentation:
info:
title: Kimai - API Docs
title: Kimai - API
description: |
JSON API for the Kimai time-tracking software: [API documentation](https://www.kimai.org/documentation/rest-api.html), [Swagger definition file](doc.json)
version: '0.7'
JSON API for the Kimai time-tracking software. Read our [API documentation](https://www.kimai.org/documentation/rest-api.html) and download the [Open API definition](doc.json) to import into your API client.
version: '1.0'
components:
securitySchemes:
apiUser:
type: apiKey
description: 'Value: {Username}'
name: X-AUTH-USER
in: header
apiToken:
type: apiKey
description: 'Value: {API Token}'
name: X-AUTH-TOKEN
in: header
bearer:
type: http
scheme: bearer
bearerFormat: KIMAI
description: API Token
security:
- X-AUTH-USER: []
X-AUTH-TOKEN: []
- bearer: []

View File

@@ -3,12 +3,7 @@ parameters:
nelmio_cors:
defaults:
allow_credentials: false
# allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
# allow_headers: ['Content-Type', 'Authorization', 'X-AUTH-USER', 'X-AUTH-TOKEN']
# allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
# expose_headers: ['Link']
# max_age: 3600
# for security reasons we do not allow CORS by default
allow_origin: []
allow_headers: []
allow_methods: []
@@ -18,8 +13,17 @@ nelmio_cors:
origin_regex: true
forced_allow_origin_value: ~
paths:
# only the API endpoints are accessible
'^/api/':
# allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_origin: ['*']
allow_headers: ['X-AUTH-USER', 'X-AUTH-TOKEN', 'Content-Type']
allow_headers: ['Content-Type', 'Authorization', 'X-AUTH-USER', 'X-AUTH-TOKEN']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
# expose_headers: ['Link']
max_age: 3600
when@dev:
nelmio_cors:
paths:
'^/api/':
allow_private_network: true

View File

@@ -0,0 +1,21 @@
framework:
rate_limiter:
session_prediction:
policy: 'fixed_window'
limit: 250
interval: '1 hour'
lock_factory: null
reset_password:
policy: 'fixed_window'
limit: 10
interval: '1 hour'
lock_factory: null
when@test:
framework:
rate_limiter:
reset_password:
policy: 'fixed_window'
limit: 100
interval: '1 minute'
lock_factory: null

View File

@@ -3,12 +3,15 @@ scheb_two_factor:
security_tokens:
- Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
- Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
- App\Saml\SamlToken
totp:
enabled: true
template: security/2fa.html.twig # Overwritten template
window: 1 # How many codes before/after the current one would be accepted as valid
# server_name: Server Name # Server name used in QR code
leeway: 29 # How many seconds the code is valid
issuer: Kimai # Issuer name used in QR code
# parameters: # Additional parameters added in the QR code
# image: 'https://my-service/img/logo.png'
two_factor_condition: App\Security\TwoFactorCondition
# TODO add: backup codes - https://symfony.com/bundles/SchebTwoFactorBundle/current/backup_codes.html
# TODO add: Trusted device feature - https://github.com/scheb/2fa/blob/6.x/doc/configuration.rst

View File

@@ -18,6 +18,10 @@ security:
security: false
api:
access_token:
token_handler: App\API\Authentication\AccessTokenHandler
success_handler: App\API\Authentication\AccessTokenSuccessHandler
remember_me: false
request_matcher: App\API\Authentication\ApiRequestMatcher
user_checker: App\Security\UserChecker
stateless: true
@@ -35,7 +39,6 @@ security:
entry_point: form_login
custom_authenticators:
- App\API\Authentication\SessionAuthenticator
- App\Saml\SamlAuthenticator
remember_me:
@@ -60,12 +63,20 @@ security:
logout:
path: logout
target: homepage
enable_csrf: false
login_throttling:
max_attempts: 5
interval: '5 minutes'
login_link:
check_route: link_login_check
signature_properties: ['id']
lifetime: 900
max_uses: 3
access_decision_manager:
# only grants access if there is no voter denying access
strategy: unanimous
allow_if_all_abstain: false
@@ -78,13 +89,13 @@ security:
access_control:
- { path: '^/auth/2fa', role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
- { path: '^/auth', roles: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)$', role: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)/auth', role: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)/login', role: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)/register', role: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)/resetting', role: PUBLIC_ACCESS }
- { path: '^/(%app_locales%)/', roles: ROLE_USER }
- { path: '^/api', roles: IS_AUTHENTICATED_REMEMBERED }
- { path: '^/{_locale}$', role: PUBLIC_ACCESS }
- { path: '^/{_locale}/auth', role: PUBLIC_ACCESS }
- { path: '^/{_locale}/login', role: PUBLIC_ACCESS }
- { path: '^/{_locale}/register', role: PUBLIC_ACCESS }
- { path: '^/{_locale}/resetting', role: PUBLIC_ACCESS }
- { path: '^/{_locale}/', roles: ROLE_USER }
- { path: '^/api', roles: IS_AUTHENTICATED }
when@test:
# this configuration simplifies testing URLs protected by the security mechanism
@@ -97,7 +108,3 @@ when@test:
cost: 4 # Lowest possible value for bcrypt
time_cost: 3 # Lowest possible value for argon
memory_cost: 10 # Lowest possible value for argon
firewalls:
secured_area:
http_basic: ~

View File

@@ -29,7 +29,6 @@ tabler:
routes:
tabler_welcome: dashboard
tabler_login: login
tabler_logout: logout
tabler_login_check: security_check
tabler_registration: registration_register
tabler_registration_register: registration_register
@@ -55,6 +54,7 @@ tabler:
columns: fas fa-table
comment: far fa-comment
configuration: fas fa-cog
contract: fas fa-balance-scale
copy: far fa-copy
create: fas fa-plus
csv: fas fa-table
@@ -77,6 +77,8 @@ tabler:
filter: fas fa-filter
help: far fa-question-circle
home: fas fa-home
info: fas fa-info-circle
import: fas fa-file-import
invoice: fas fa-file-contract
invoice-template: fas fa-file-signature
left: fas fa-chevron-left
@@ -97,6 +99,7 @@ tabler:
password: fas fa-key
pause: fas fa-pause
pause-small: far fa-pause-circle
pending: fas fa-hourglass-half
pin: fas fa-thumbtack
pdf: fas fa-file-pdf
permissions: fas fa-user-lock
@@ -106,9 +109,11 @@ tabler:
profile: fas fa-user-edit
profile-stats: far fa-chart-bar
project: fas fa-briefcase
repeat: fas fa-redo-alt
repeat: fas fa-repeat
reporting: far fa-chart-bar
report: far fa-chart-bar
review: fas fa-user-check
rejected: fas fa-ban
right: fas fa-chevron-right
right2: fas fa-angle-double-right
roles: fas fa-user-shield
@@ -116,7 +121,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
@@ -136,4 +141,5 @@ tabler:
weekly-times: fas fa-th
widget_add: fas fa-folder-plus
widget_remove: fas fa-folder-minus
work_times: fas fa-calculator
xlsx: fas fa-file-excel

View File

@@ -1,4 +1,6 @@
framework:
# https://symfony.com/doc/current/reference/configuration/framework.html#enabled-locales
enabled_locales: '%kimai_locales%'
default_locale: '%locale%'
translator:
default_path: '%kernel.project_dir%/translations'

View File

@@ -1,9 +1,7 @@
controllers:
resource: ../src/Controller/
type: annotation
type: attribute
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
@@ -19,26 +17,24 @@ api.swagger:
api:
resource: ../src/API/
type: annotation
type: attribute
prefix: /api
auth:
resource: ../src/Controller/Auth/
type: annotation
type: attribute
prefix: /auth
security:
resource: ../src/Controller/Security/
type: annotation
type: attribute
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
kernel:
resource: ../src/Kernel.php
type: annotation
type: attribute
home:
path: /
@@ -49,8 +45,6 @@ home:
homeLocale:
path: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
_locale: '%locale%'

View File

@@ -1,7 +1,5 @@
_errors:
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
prefix: /{_locale}/_error
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'

View File

@@ -1,7 +1,5 @@
app.test.active_entries:
path: /{_locale}/layou/active_entries
controller: App\Controller\LayoutController::activeEntries
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'

View File

@@ -1,8 +1,7 @@
parameters:
locale: en
# the original list of all locales is the next line, it can be used to regenerate the locale list in case new locales will be added
#app_locales: ar|cs|da|de|el|en|eo|es|eu|fa|fi|fo|fr|he|hr|hu|it|ja|ko|nb_NO|nl|pl|pt|ro|ru|sk|sv|tr|uk|vi|zh_CN|zh_Hant
app_locales: ar|cs|da|de|el|en|eo|es|eu|fa|fi|fo|fr|he|hr|hu|it|ja|ko|nb_NO|nl|pl|pt|pt_BR|ro|ru|sk|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_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_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_NL|en_NR|en_NU|en_NZ|en_PG|en_PH|en_PK|en_PN|en_PR|en_PW|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_EC|es_ES|es_GQ|es_GT|es_HN|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_KP|ko_KR|nl_AW|nl_BE|nl_BQ|nl_CW|nl_NL|nl_SR|nl_SX|pl_PL|pt_AO|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|vi_VN
# can be regenerated with: bin/console kimai:reset:locales
kimai_locales: ['ar', 'ca', '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', 'ca_AD', 'ca_ES', 'ca_FR', 'ca_IT', '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
@@ -16,20 +15,23 @@ services:
$projectDirectory: '%kernel.project_dir%'
$kernelEnvironment: '%kernel.environment%'
# make classes in src/ available to be used as services
# creates one service per class whose id is the fully-qualified class name
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude:
- '../src/API/Model/'
- '../src/DependencyInjection/'
- '../src/Doctrine/Extensions/'
- '../src/Entity/'
- '../src/Event/'
- '../src/Form/Model/'
- '../src/Model/'
- '../src/Repository/Loader/'
- '../src/Repository/Paginator/'
- '../src/Repository/Query/'
- '../src/Repository/Result/'
- '../src/Event/'
- '../src/Model/'
- '../src/WorkingTime/Calculator/'
- '../src/Kernel.php'
- '../src/Constants.php'
@@ -60,18 +62,6 @@ services:
arguments:
$cacheDirectory: '%kernel.cache_dir%'
App\Plugin\PluginManager:
arguments: [!tagged kimai.plugin]
App\Validator\Constraints\TimesheetValidator:
arguments: [!tagged timesheet.validator]
App\Validator\Constraints\ProjectValidator:
arguments: [!tagged project.validator]
App\Validator\Constraints\QuickEntryTimesheetValidator:
arguments: [!tagged timesheet.validator]
App\Utils\FileHelper:
arguments:
$dataDir: '%kimai.data_dir%'
@@ -83,41 +73,19 @@ services:
arguments:
$mailer: '@App\Mail\KimaiMailer'
# ================================================================================
# DATABASE
# ================================================================================
# updates timesheet records and apply configured rate & rounding rules
App\Doctrine\TimesheetSubscriber:
class: App\Doctrine\TimesheetSubscriber
arguments: [!tagged timesheet.calculator]
tags:
- { name: doctrine.event_subscriber, priority: 50 }
# updates timestampable columns (higher priority, so the TimesheetSubscriber will be executed later)
Gedmo\Timestampable\TimestampableListener:
class: Gedmo\Timestampable\TimestampableListener
tags:
- { name: doctrine.event_subscriber, priority: 60 }
calls:
- [ setAnnotationReader, [ "@annotation_reader" ] ]
# ================================================================================
# TIMESHEET RECORD CALCULATOR
# ================================================================================
App\Timesheet\RoundingService:
arguments:
$roundingModes: !tagged timesheet.rounding_mode
# this is currently required, as local.yaml allows to configure several rules,
# while the database system only allows one rounding rule
$rules: '%kimai.timesheet.rounding%'
App\Timesheet\RateService:
arguments: ['%kimai.timesheet.rates%']
App\Timesheet\TrackingModeService:
arguments:
$modes: !tagged timesheet.tracking_mode
# ================================================================================
# SECURITY & VOTER
# ================================================================================
@@ -135,7 +103,9 @@ services:
# SAML Services
# ================================================================================
App\Saml\SamlProvider:
arguments: ['@App\Repository\UserRepository', '@security.user.provider.concrete.kimai_internal', '@App\Configuration\SamlConfigurationInterface']
arguments:
$userProvider: '@security.user.provider.concrete.kimai_internal'
$configuration: '@App\Configuration\SamlConfigurationInterface'
# ================================================================================
# REPOSITORIES
@@ -224,3 +194,25 @@ services:
class: App\Repository\BookmarkRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: ['App\Entity\Bookmark']
App\Repository\WorkingTimeRepository:
class: App\Repository\WorkingTimeRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: ['App\Entity\WorkingTime']
App\Repository\AccessTokenRepository:
class: App\Repository\AccessTokenRepository
factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: ['App\Entity\AccessToken']
monolog.formatter.kimai:
class: Monolog\Formatter\LineFormatter
arguments:
- "[%%datetime%%] [%%extra.channel%%] %%level_name%%: %%message%% %%context%% %%extra%%\n"
- "Y-m-d H:i:s"
monolog.formatter.deprecation:
class: Monolog\Formatter\LineFormatter
arguments:
- "[%%datetime%%] %%message%% %%context%%\n"
- "Y-m-d H:i:s"

View File

@@ -1,6 +1,6 @@
parameters:
locale: en
app_locales: ar|cs|de|de_CH|da|en|eo|es|eu|fr|he|hu|it|ja|ko|nl|pl|pt_BR|ro|ru|sk|sv|tr|vi|zh_CN
kimai_locales: ['ar', 'cs', 'de', 'de_CH', 'da', 'en', 'eo', 'es', 'eu', 'fr', 'he', 'hu', 'it', 'ja', 'ko', 'nl', 'pl', 'pt_BR', 'ro', 'ru', 'sk', 'sv', 'tr', 'vi', 'zh_CN']
services:
_defaults:
@@ -23,7 +23,3 @@ services:
App\User\UserService:
public: true
arguments: ['@App\Repository\UserRepository', '@event_dispatcher', '@validator', '@App\Configuration\SystemConfiguration', '@security.user_password_hasher']
App\Plugin\PluginManager:
public: true
arguments: [!tagged kimai.plugin]

View File

@@ -0,0 +1,38 @@
<?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 DoctrineMigrations;
use App\Doctrine\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* @version 2.x
*/
final class <className> extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
$this->abortIf(true, 'Migration was auto-generated, adapt to your needs before running it.');
<up>
}
public function down(Schema $schema): void
{
$this->abortIf(true, 'Migration was auto-generated, adapt to your needs before running it.');
<down>
}<override>
}

View File

@@ -29,20 +29,20 @@ final class Version20190706224211 extends AbstractMigration
public function up(Schema $schema): void
{
$timesheetMeta = $schema->getTable('kimai2_timesheet_meta');
$timesheetMeta->changeColumn('visible', ['notnull' => true, 'default' => false]);
$timesheetMeta->changeColumn('timesheet_id', ['notnull' => true]);
$timesheetMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$timesheetMeta->modifyColumn('timesheet_id', ['notnull' => true]);
$projectMeta = $schema->getTable('kimai2_projects_meta');
$projectMeta->changeColumn('visible', ['notnull' => true, 'default' => false]);
$projectMeta->changeColumn('project_id', ['notnull' => true]);
$projectMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$projectMeta->modifyColumn('project_id', ['notnull' => true]);
$customerMeta = $schema->getTable('kimai2_customers_meta');
$customerMeta->changeColumn('visible', ['notnull' => true, 'default' => false]);
$customerMeta->changeColumn('customer_id', ['notnull' => true]);
$customerMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$customerMeta->modifyColumn('customer_id', ['notnull' => true]);
$activityMeta = $schema->getTable('kimai2_activities_meta');
$activityMeta->changeColumn('visible', ['notnull' => true, 'default' => false]);
$activityMeta->changeColumn('activity_id', ['notnull' => true]);
$activityMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$activityMeta->modifyColumn('activity_id', ['notnull' => true]);
}
public function down(Schema $schema): void

View File

@@ -41,6 +41,6 @@ final class Version20210316224358 extends AbstractMigration
public function down(Schema $schema): void
{
$this->addSql('DROP TABLE kimai2_bookmarks');
$schema->dropTable('kimai2_bookmarks');
}
}

View File

@@ -51,7 +51,7 @@ final class Version20210802152814 extends AbstractMigration
public function down(Schema $schema): void
{
$timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => false]);
$timesheet->modifyColumn('date_tz', ['notnull' => false]);
$this->preventEmptyMigrationWarning();
}

View File

@@ -27,14 +27,14 @@ final class Version20210802160837 extends AbstractMigration
public function up(Schema $schema): void
{
$timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => true]);
$timesheet->modifyColumn('date_tz', ['notnull' => true]);
$timesheet->addIndex(['date_tz', 'user'], 'IDX_4F60C6B1BDF467148D93D649');
}
public function down(Schema $schema): void
{
$timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => false]);
$timesheet->modifyColumn('date_tz', ['notnull' => false]);
$timesheet->dropIndex('IDX_4F60C6B1BDF467148D93D649');
}
}

View File

@@ -42,7 +42,7 @@ final class Version20230126002049 extends AbstractMigration
$users = $schema->getTable('kimai2_users');
if (!$users->hasColumn('totp_secret')) {
$users->addColumn('totp_secret', 'string', ['notnull' => false, 'default' => null]);
$users->addColumn('totp_secret', 'string', ['length' => 255, 'notnull' => false, 'default' => null]);
$users->addColumn('totp_enabled', 'boolean', ['notnull' => true, 'default' => false]);
}
if (!$users->hasColumn('system_account')) {
@@ -85,7 +85,7 @@ final class Version20230126002049 extends AbstractMigration
$this->addSql("UPDATE kimai2_configuration SET `value` = '15' WHERE `name` = 'timesheet.time_increment' and `value` = '0'");
$this->addSql("UPDATE kimai2_configuration SET `value` = '5' WHERE `name` = 'timesheet.time_increment' and `value` IN ('1', '2', '3', '4')");
$this->addSql("UPDATE kimai2_configuration SET `value` = '0' WHERE `name` = 'user.registration'");
$this->addSql("UPDATE kimai2_roles SET `name` = UPPER(`name`)");
$this->addSql('UPDATE kimai2_roles SET `name` = UPPER(`name`)');
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'service-date' WHERE `renderer` = 'freelancer'");
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'invoice' WHERE `renderer` = 'default'");
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'default' WHERE `renderer` = 'default-pdf'");

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
/*
* 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 DoctrineMigrations;
use App\Doctrine\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* @version 2.0.20
*/
final class Version20230327143628 extends AbstractMigration
{
public function getDescription(): string
{
return 'Creates the working times table';
}
public function up(Schema $schema): void
{
$workingTimes = $schema->createTable('kimai2_working_times');
$workingTimes->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]);
$workingTimes->addColumn('user_id', 'integer', ['notnull' => true]);
$workingTimes->addColumn('approved_by', 'integer', ['notnull' => false, 'default' => null]);
$workingTimes->addColumn('date', 'date', ['notnull' => true]);
$workingTimes->addColumn('expected', 'integer', ['notnull' => true]);
$workingTimes->addColumn('actual', 'integer', ['notnull' => true]);
$workingTimes->addColumn('approved_at', 'datetime', ['notnull' => false, 'default' => null]);
$workingTimes->setPrimaryKey(['id']);
$workingTimes->addIndex(['user_id'], 'IDX_F95E4933A76ED395');
$workingTimes->addIndex(['approved_by'], 'IDX_F95E49334EA3CB3D');
$workingTimes->addUniqueIndex(['user_id', 'date'], 'UNIQ_F95E4933A76ED395AA9E377A');
$workingTimes->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_F95E4933A76ED395');
$workingTimes->addForeignKeyConstraint('kimai2_users', ['approved_by'], ['id'], ['onDelete' => 'SET NULL'], 'FK_F95E49334EA3CB3D');
}
public function down(Schema $schema): void
{
$workingTimes = $schema->getTable('kimai2_working_times');
$workingTimes->removeForeignKey('FK_F95E4933A76ED395');
$workingTimes->removeForeignKey('FK_F95E49334EA3CB3D');
$schema->dropTable('kimai2_working_times');
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/*
* 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 DoctrineMigrations;
use App\Doctrine\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* @version 2.0.26
*/
final class Version20230606125948 extends AbstractMigration
{
public function getDescription(): string
{
return 'Adds the visible column for tags';
}
public function up(Schema $schema): void
{
$tags = $schema->getTable('kimai2_tags');
$tags->addColumn('visible', 'boolean', ['notnull' => false, 'default' => true]);
}
public function down(Schema $schema): void
{
$tags = $schema->getTable('kimai2_tags');
$tags->dropColumn('visible');
}
}

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