Compare commits

...

54 Commits
0.1 ... 0.2

Author SHA1 Message Date
Kevin Papst
f563e0703d prepare v0.2 release #177 (#178)
* added CHANGELOG.md and support for github-changelog-generator
2018-06-24 01:18:55 +02:00
Kevin Papst
c3251ee435 various documentation updates (#176)
* updated README
* improved CONTRIBUTING guidelines
* improved wording on developer docu
2018-06-23 21:20:20 +02:00
Kevin Papst
e9e61afc76 code styles: header_comment and ordered_imports (#175) 2018-06-23 11:41:58 +02:00
Kevin Papst
cd7cbeae88 improved code styles #158 (#172)
* use php-cs-fixer instead of phpcodesniffer
* updated scrutinizer config
* adjusted code yules to all files
* updated CONTRIBUTING guidelines
2018-06-22 21:09:10 +02:00
Kevin Papst
773d27bb0e set default locale for tests (#171) 2018-06-21 22:44:32 +02:00
Kevin Papst
0eaa81578a hide success notification after 5 seconds #169 (#170) 2018-06-21 18:47:13 +02:00
Kevin Papst
3dc054b839 help text and link for form labels #138 (#143)
* added help for timesheet duration form field - fixes #138
* added label option to link to manual chapter
* created docu chapter "timesheet" and added duration mode docu
* allow field and form option "documentation" to link to chapters in the documentation
2018-06-21 18:25:11 +02:00
Kevin Papst
8c686b0714 Added validation for end date before start date (#167)
* added validation for end date before start date
* added unit test for new validations
2018-06-20 23:27:56 +02:00
Kevin Papst
071abc8fc8 Update issue templates 2018-06-20 21:37:57 +02:00
Kevin Papst
75a6bf3ef6 Updated security expressions #148 (#166)
* replace has_role() with is_granted()
* added basic integration test classes for main controller
* added basic integration test classes for admin controller
2018-06-19 22:08:44 +02:00
Kevin Papst
856e7ccaeb Composer updates (#165)
* updated composer dependencies
* updated README about composer install
2018-06-18 23:13:29 +02:00
Kevin Papst
bfa32a90db Update to Symfony 4.1 #149 (#160)
* updated to Symfony 4.1 #149
* updated to phpunit 7 #149
* downgrade ocramius/proxy-manager for PHP 7.1 compatibility #149
* fixed symfony deprecations #149
* replaced AdvancedUserInterface with custom user checker
* code sniffer fixes
2018-06-18 22:26:00 +02:00
Kevin Papst
4e629fcaf8 some wording changes 2018-06-18 21:37:39 +02:00
Kevin Papst
01bce05da4 added scrutinizer config #158 (#161) 2018-06-08 00:16:12 +02:00
Kevin Papst
8a19af4efc Travis integration #120 (#159)
* fixed php versions used in travis #120
* fixed broken test #120
* updated developer docu
2018-06-06 21:36:24 +02:00
Kevin Papst
6eef9f6f37 Mobile alignments and toolbar #151 (#157)
* improved toolbar position #151
* fixed alignments on mobile #151
* fixed moment js #151
2018-06-05 23:15:25 +02:00
Kevin Papst
0445a255d0 added local config to overwrite settings #153 (#156) 2018-06-05 23:06:47 +02:00
Kevin Papst
451cf4cd1d Filter in hidden toolbar - improved mobile #151 (#155)
* improved toolbar: hide data table form in collapsible + filter button
* added collapsible area for toolbar form #151
2018-06-05 21:49:13 +02:00
Kevin Papst
7206d064a5 Improved mobile view #151 (#150)
- fixed group by for mysql mode
- only user can edit own prefs
- updated installation README
- pagerfanta shows less links
- improved manual tab
- moved user profile link to pref tabs
- added menu links to top navbar
- moved page actions to breadcrumb position
- integrated daterangepicker and improved toolbar forms
- bugfix for time rounding
2018-06-05 21:28:25 +02:00
Kevin Papst
db5b6f8e2e added russian translation #95 (#147)
* added russian translation #95
* added config for duration_only mode and adjusted timesheet views #131
2018-06-02 19:57:12 +02:00
Kevin Papst
9d9860e495 bugfix for duration_only mode #137 (#142)
* replaced durationForEntry with duration filter
* fixed duration problem - fixes #137
2018-06-02 19:39:03 +02:00
Kevin Papst
1c0f8cdad1 Bugfix importer (#145) (#146)
* Fix importer #145
2018-06-01 15:06:29 +02:00
Simon Schaufelberger
4af0e277b4 Make the back link appear like a normal link instead of a button (#139) 2018-02-18 12:12:24 +01:00
Kevin Papst
5a4bb0d081 Duration only mode #131 (#134) 2018-02-10 22:19:49 +01:00
Simon Schaufelberger
93e1cd5095 Secure create-user command #123 (#127)
* ask the user for the password #123
* added integration test #123
2018-02-10 19:11:30 +01:00
Simon Schaufelberger
5527f29caf Use short array syntax (#135) 2018-02-10 19:05:19 +01:00
Simon Schaufelberger
4c6158c1ea Merge pull request #132 from kevinpapst/inline-docu-129
added controller to render markdown documentation #129
2018-02-07 21:41:42 +01:00
Kevin Papst
6431fbecf6 code review fixes #129 2018-02-07 21:29:35 +01:00
Kevin Papst
29699572bd added controller to render markdown documentation #129 2018-02-07 15:07:53 +01:00
Kevin Papst
2e60e14132 added rounding rules and hourly rates factor #112 (#128)
* added unit tests and documentation #112
* fixed DashboardController
* added CONTRIBUTION guidelines
* fixed license year
2018-02-07 12:51:00 +01:00
Simon Schaufelberger
65790f1fb7 using new license header #124 (#119) 2018-02-03 18:23:47 +01:00
Simon Schaufelberger
76d4cba596 Add github issue and pull request template (#118) 2018-02-03 18:19:51 +01:00
Simon Schaufelberger
974cee0b6e compile assets with hash after filename #125 (#126) 2018-02-03 17:52:26 +01:00
Kevin Papst
7deaba8368 added webpack-encore for managing frontend assets #113 (#122)
* updated installation docu #113
* rewritten login page #113
* added icheck plugin #113
* changed to YesNoType in edit forms #113
* updated CONTRIBUTING.md #113
* added start of developer docu #113
* added compile scripts and compiled assets #113
2018-02-01 22:26:19 +01:00
Kevin Papst
e35d73eab5 fixed short invoice calculator (#114)
* fixed money display and address field for InvoiceTemplate entity
* added quick start button for users without active records
* rearranged columns on project and customer admin page
* improved extensions docu
2018-01-28 12:08:44 +01:00
Kevin Papst
9bbaf0ec71 added first docu on extending kimai with bundles #106 (#109) 2018-01-27 11:21:52 +01:00
Kevin Papst
1958bb9d09 added order number to projects #107 (#108) 2018-01-25 21:42:18 +01:00
Kevin Papst
7f5b5ac254 added short invoice calculator and timesheet invoice template #104 (#105) 2018-01-23 22:30:41 +01:00
Kevin Papst
50b5e93a10 added command to import data from kimai v1 #102 (#103) 2018-01-23 00:23:41 +01:00
Kevin Papst
6ae9bc4df5 added layout and translation to error pages #100 (#101) 2018-01-21 22:53:10 +01:00
Kevin Papst
4cbc5391c0 added basic invoice rendering #97 #93 (#99) 2018-01-21 22:50:46 +01:00
Kevin Papst
9a161b8fd9 added remember me feature #53 (#98)
cleanup event subscriber
2018-01-17 19:55:26 +01:00
Kevin Papst
7df21f3f5a code-cleanup: removed unused classes, added role constants, phpcs fixes (#96) 2018-01-16 23:56:55 +01:00
Kevin Papst
0a65965187 load doctrine extensions during kernel bootstrap #84 (#92) 2018-01-16 21:35:23 +01:00
Kevin Papst
3f221fcdb8 support theme options via user preferences #89 (#91) 2018-01-15 22:58:07 +01:00
Kevin Papst
827b1ae9ad fixed dynamic user preferences #9
added missing Chart.min.js
2018-01-14 23:02:50 +01:00
Kevin Papst
49d8796f6b added dynamic user preferences #7 #9 (#90)
- fixed user settings database #9
- added dynamic user preferences #9
- added form to edit user preferences #9
- removed user language #7
2018-01-14 22:47:20 +01:00
Kevin Papst
023fef6a70 added control sidebar #10 (#87)
- added configurable sidebar #10
- added language switch in sidebar preferences tab #10
- added sidebar tab with kimai beta-info message #10
- use trait for repositories
- improved README
2018-01-14 01:36:07 +01:00
Kevin Papst
d5e689e307 code cleanup 2018-01-13 00:20:41 +01:00
Kevin Papst
fc9ce52d69 removed unused files #74 2018-01-13 00:19:23 +01:00
Kevin Papst
c7935da16a added english translation #8 (#82)
* reformatted translation file #8
* set default language to en #8
* added english translations #8
2018-01-12 22:21:15 +01:00
Kevin Papst
1833a6632a skip broken tests, added browserkit for integration tests 2018-01-12 21:21:43 +01:00
Kevin Papst
4d7fe3d595 fixes for symfony4 #74 #81 2018-01-12 21:07:20 +01:00
Kevin Papst
a87355695e upgraded to symfony 4 #74 (#81) 2018-01-12 20:39:07 +01:00
401 changed files with 25269 additions and 9130 deletions

10
.editorconfig Normal file
View File

@@ -0,0 +1,10 @@
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = LF
[*.php]
indent_style = space
indent_size = 4

28
.env.dist Normal file
View File

@@ -0,0 +1,28 @@
# This file is a "template" of which env vars need to be defined for your application
# Copy this file to .env file for development, create environment variables when deploying to production
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
# KIMAI DEFAULT ENV VARS
DATABASE_PREFIX=kimai2_
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=c88c14fa70a424e7a12d459b9dd9df7f
#TRUSTED_PROXIES=127.0.0.1,127.0.0.2
#TRUSTED_HOSTS=localhost,example.com
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data/kimai.sqlite"
# Configure your db driver and server_version in config/packages/doctrine.yaml
# DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/kimai.sqlite
###< doctrine/doctrine-bundle ###
###> symfony/swiftmailer-bundle ###
# For Gmail as a transport, use: "gmail://username:password@localhost"
# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
# Delivery is disabled by default via "null://localhost"
MAILER_URL=null://localhost
###< symfony/swiftmailer-bundle ###

22
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,22 @@
## Description
## Expected Behavior
## Actual Behavior
## Possible Fix
## Steps to Reproduce
1.
2.
3.
4.
## Your Environment
* Version:
* Browser Name and version:
* Operating System and version (desktop or mobile):

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

14
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,14 @@
## Description
## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist
- [ ] My code follows the code style
- [ ] All files have a license header
- [ ] All methods have a doc header with type declarations
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes

View File

@@ -0,0 +1,2 @@
unreleased=true
future-release=0.2

95
.gitignore vendored
View File

@@ -1,57 +1,48 @@
# Cache and logs (Symfony2)
/app/cache/*
/app/logs/*
!app/cache/.gitkeep
!app/logs/.gitkeep
# Email spool folder
/app/spool/*
# Cache, session files and logs (Symfony3)
/var/cache/*
/var/logs/*
/var/sessions/*
!var/cache/.gitkeep
!var/logs/.gitkeep
!var/sessions/.gitkeep
# Parameters
/app/config/parameters.yml
/app/config/parameters.ini
# Managed by Composer
/app/bootstrap.php.cache
/var/bootstrap.php.cache
/bin/*
!bin/console
!bin/symfony_requirements
/vendor/
# Assets and user uploads
/web/bundles/
/web/uploads/
# Assets managed by Bower
/web/assets/vendor/
# PHPUnit
/app/phpunit.xml
/phpunit.xml
# Build data
/build/
# Composer PHAR
/composer.phar
# Backup entities generated with doctrine:generate:entities command
*/Entity/*~
# ========== KIMAI ==========
# IDE
.idea/
# SQLite files
/app/data/timesheet.sqlite
/bin/*
!bin/console
/config/packages/local.yaml
# generated install and setup files
/web/theme/
/var/data/kimai.sqlite
/var/coverage/
/var/cache/*
!var/cache/.gitkeep
/var/log/*
!var/log/.gitkeep
/var/sessions/*
!var/sessions/.gitkeep
# ========== KIMAI ==========
###> symfony/framework-bundle ###
.env
/public/bundles/
/vendor/
###< symfony/framework-bundle ###
###> symfony/web-server-bundle ###
.web-server-pid
###< symfony/web-server-bundle ###
###> phpunit/phpunit ###
/phpunit.xml
###< phpunit/phpunit ###
###> friendsofphp/php-cs-fixer ###
.php_cs
.php_cs.cache
###< friendsofphp/php-cs-fixer ###
###> symfony/webpack-encore-pack ###
/node_modules/
###< symfony/webpack-encore-pack ###
###> symfony/phpunit-bridge ###
.phpunit
/phpunit.xml
###< symfony/phpunit-bridge ###

153
.php_cs.dist Normal file
View File

@@ -0,0 +1,153 @@
<?php
$fileHeaderComment = <<<COMMENT
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.
COMMENT;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'encoding' => true,
'full_opening_tag' => true,
'blank_line_after_namespace' => true,
'braces' => true,
'class_definition' => true,
'elseif' => true,
'function_declaration' => true,
'indentation_type' => true,
'line_ending' => true,
'lowercase_constants' => true,
'lowercase_keywords' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'header_comment' => ['header' => $fileHeaderComment, 'separate' => 'both'],
'no_php4_constructor' => true,
'ordered_imports' => true,
'no_break_comment' => true,
'no_closing_tag' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'single_blank_line_at_eof' => true,
'single_class_element_per_statement' => ['elements' => ['property']],
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'array_syntax' => [
'syntax' => 'short'
],
'binary_operator_spaces' => true,
'blank_line_after_opening_tag' => true,
'blank_line_before_statement' => [
'statements' => ['return'],
],
'cast_spaces' => true,
'class_attributes_separation' => ['elements' => ['method']],
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => true,
'function_typehint_space' => true,
'include' => true,
'lowercase_cast' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'native_function_casing' => true,
'new_with_braces' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => ['tokens' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
]],
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ['use' => 'echo'],
'no_multiline_whitespace_around_double_arrow' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_around_offset' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unused_imports' => true,
'no_whitespace_before_comma_in_array' => true,
'no_whitespace_in_blank_line' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
'php_unit_fqcn_annotation' => true,
'phpdoc_align' => [
'align' => 'left',
'tags' => [
'method',
'param',
'property',
'return',
'throws',
'type',
'var',
],
],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag' => true,
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => false,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => false,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'protected_to_private' => true,
'return_type_declaration' => true,
'semicolon_after_instruction' => true,
'short_scalar_cast' => true,
'single_blank_line_before_namespace' => true,
'single_line_comment_style' => [
'comment_types' => ['hash'],
],
'single_quote' => true,
'space_after_semicolon' => [
'remove_in_empty_for_expressions' => true,
],
'standardize_increment' => true,
'standardize_not_equals' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => false,
'trim_array_spaces' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
'yoda_style' => false,
'ternary_to_null_coalescing' => true,
'visibility_required' => ['elements' => [
'const',
'method',
'property',
]],
])
->setFinder(
PhpCsFixer\Finder::create()
->in([
__DIR__ . '/src/',
__DIR__ . '/tests/',
])
)
->setFormat('checkstyle')
;

40
.scrutinizer.yml Normal file
View File

@@ -0,0 +1,40 @@
build:
environment:
node: v8.11.2
nodes:
analysis:
tests:
override:
- js-scrutinizer-run
- php-scrutinizer-run
tests:
tests:
override:
-
command: 'vendor/bin/phpunit --exclude-group integration --coverage-clover=unit tests/'
coverage:
file: 'unit'
format: 'clover'
-
command: 'vendor/bin/phpunit --group integration --coverage-clover=integration tests/'
coverage:
file: 'integration'
format: 'clover'
-
command: 'bin/console kimai:phpcs --checkstyle=checkstyle'
analysis:
file: 'checkstyle'
format: 'php-cs-checkstyle'
filter:
excluded_paths:
- '.github/'
- 'bin/'
- 'config/'
- 'public/'
- 'templates/'
- 'translations/'
- 'var/'
dependency_paths:
- 'node_modules/'
- 'vendor/'

View File

@@ -8,12 +8,8 @@ cache:
matrix:
fast_finish: true
include:
- php: 5.5
- php: 5.6
- php: 7.0
- php: hhvm
allow_failures:
- php: hhvm
- php: 7.1
- php: 7.2
before_install:
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi
@@ -23,4 +19,5 @@ install:
- composer install
script:
- phpunit
- vendor/bin/phpunit --exclude-group integration tests/
- vendor/bin/phpunit --group integration tests/

177
CHANGELOG.md Normal file
View File

@@ -0,0 +1,177 @@
# Change Log
## [0.2](https://github.com/kevinpapst/kimai2/tree/0.2) (2018-06-24)
[Full Changelog](https://github.com/kevinpapst/kimai2/compare/0.1...0.2)
**Fixed bugs:**
- Prevent end time before start time [\#152](https://github.com/kevinpapst/kimai2/issues/152)
- Importing old data fails [\#145](https://github.com/kevinpapst/kimai2/issues/145)
- Translate LanguageType choices [\#83](https://github.com/kevinpapst/kimai2/issues/83)
- Change to users language after login [\#7](https://github.com/kevinpapst/kimai2/issues/7)
- Mobile alignments and toolbar \#151 [\#157](https://github.com/kevinpapst/kimai2/pull/157) ([kevinpapst](https://github.com/kevinpapst))
- Improved mobile view \#151 [\#150](https://github.com/kevinpapst/kimai2/pull/150) ([kevinpapst](https://github.com/kevinpapst))
**Closed issues:**
- Hide notifications after some seconds [\#169](https://github.com/kevinpapst/kimai2/issues/169)
- Setup Scrutinizer to run code sniffer [\#158](https://github.com/kevinpapst/kimai2/issues/158)
- Local config to overwrite settings [\#153](https://github.com/kevinpapst/kimai2/issues/153)
- Improve mobile view [\#151](https://github.com/kevinpapst/kimai2/issues/151)
- Upgrade to Symfony 4.1 [\#149](https://github.com/kevinpapst/kimai2/issues/149)
- Replace has\_role\(\) with is\_granted\(\) [\#148](https://github.com/kevinpapst/kimai2/issues/148)
- Integrate FOSUserBundle \(for registration, password-reset, etc.\) [\#144](https://github.com/kevinpapst/kimai2/issues/144)
- Add help text to form elements [\#138](https://github.com/kevinpapst/kimai2/issues/138)
- Duration mode: creating new timesheet records prefills duration with some seconds [\#137](https://github.com/kevinpapst/kimai2/issues/137)
- Add duration-only mode [\#131](https://github.com/kevinpapst/kimai2/issues/131)
- Add help controller [\#129](https://github.com/kevinpapst/kimai2/issues/129)
- \[RFC\] Encore: configureFilenames with hash after filename instead of in the filename [\#125](https://github.com/kevinpapst/kimai2/issues/125)
- \[RFC\] Kimai license header [\#124](https://github.com/kevinpapst/kimai2/issues/124)
- Secure create-user command [\#123](https://github.com/kevinpapst/kimai2/issues/123)
- Setup travis to run phpunit tests [\#120](https://github.com/kevinpapst/kimai2/issues/120)
- Add command for building a production release [\#115](https://github.com/kevinpapst/kimai2/issues/115)
- Add webpack and webpack-encore for frontend assets [\#113](https://github.com/kevinpapst/kimai2/issues/113)
- Add time rounding option [\#112](https://github.com/kevinpapst/kimai2/issues/112)
- Add field order number in Projects [\#107](https://github.com/kevinpapst/kimai2/issues/107)
- Create docu for invoice templates [\#106](https://github.com/kevinpapst/kimai2/issues/106)
- Add invoice template: timesheet [\#104](https://github.com/kevinpapst/kimai2/issues/104)
- Add importer from Kimai v1 [\#102](https://github.com/kevinpapst/kimai2/issues/102)
- Setup error pages [\#100](https://github.com/kevinpapst/kimai2/issues/100)
- Add basic HTML invoice rendering [\#97](https://github.com/kevinpapst/kimai2/issues/97)
- Add russian translation [\#95](https://github.com/kevinpapst/kimai2/issues/95)
- Filter user in timesheet admin [\#93](https://github.com/kevinpapst/kimai2/issues/93)
- Support to switch theme settings [\#89](https://github.com/kevinpapst/kimai2/issues/89)
- Roles should become a real table [\#86](https://github.com/kevinpapst/kimai2/issues/86)
- Fix Doctrine extensions config loader [\#84](https://github.com/kevinpapst/kimai2/issues/84)
- Upgrade to Symfony 4 and Flex [\#74](https://github.com/kevinpapst/kimai2/issues/74)
- Add remember me login [\#53](https://github.com/kevinpapst/kimai2/issues/53)
- Add preferences sidebar [\#10](https://github.com/kevinpapst/kimai2/issues/10)
- Add user settings [\#9](https://github.com/kevinpapst/kimai2/issues/9)
- Add english translation [\#8](https://github.com/kevinpapst/kimai2/issues/8)
- Add configurable system configuration [\#6](https://github.com/kevinpapst/kimai2/issues/6)
**Merged pull requests:**
- various documentation updates [\#176](https://github.com/kevinpapst/kimai2/pull/176) ([kevinpapst](https://github.com/kevinpapst))
- code styles: header\_comment and ordered\_imports [\#175](https://github.com/kevinpapst/kimai2/pull/175) ([kevinpapst](https://github.com/kevinpapst))
- Code sniffer rules \#158 [\#172](https://github.com/kevinpapst/kimai2/pull/172) ([kevinpapst](https://github.com/kevinpapst))
- Set default locale for unit-tests [\#171](https://github.com/kevinpapst/kimai2/pull/171) ([kevinpapst](https://github.com/kevinpapst))
- Hide success notification after 5 seconds [\#170](https://github.com/kevinpapst/kimai2/pull/170) ([kevinpapst](https://github.com/kevinpapst))
- Added validation for end date before start date [\#167](https://github.com/kevinpapst/kimai2/pull/167) ([kevinpapst](https://github.com/kevinpapst))
- Security expression \#148 [\#166](https://github.com/kevinpapst/kimai2/pull/166) ([kevinpapst](https://github.com/kevinpapst))
- Composer install [\#165](https://github.com/kevinpapst/kimai2/pull/165) ([kevinpapst](https://github.com/kevinpapst))
- added scrutinizer config \#158 [\#161](https://github.com/kevinpapst/kimai2/pull/161) ([kevinpapst](https://github.com/kevinpapst))
- Update to Symfony 4.1 \#149 [\#160](https://github.com/kevinpapst/kimai2/pull/160) ([kevinpapst](https://github.com/kevinpapst))
- Updated README [\#159](https://github.com/kevinpapst/kimai2/pull/159) ([kevinpapst](https://github.com/kevinpapst))
- Local config \#153 [\#156](https://github.com/kevinpapst/kimai2/pull/156) ([kevinpapst](https://github.com/kevinpapst))
- Filter in hidden toolbar - improved mobile \#151 [\#155](https://github.com/kevinpapst/kimai2/pull/155) ([kevinpapst](https://github.com/kevinpapst))
- added russian translation \#95 [\#147](https://github.com/kevinpapst/kimai2/pull/147) ([kevinpapst](https://github.com/kevinpapst))
- Bugfix importer \(\#145\) [\#146](https://github.com/kevinpapst/kimai2/pull/146) ([kevinpapst](https://github.com/kevinpapst))
- help text and link for form labels \#138 [\#143](https://github.com/kevinpapst/kimai2/pull/143) ([kevinpapst](https://github.com/kevinpapst))
- bugfix for duration\_only mode \#137 [\#142](https://github.com/kevinpapst/kimai2/pull/142) ([kevinpapst](https://github.com/kevinpapst))
- Make the back link appear like a normal link instead of a button [\#139](https://github.com/kevinpapst/kimai2/pull/139) ([simonschaufi](https://github.com/simonschaufi))
- Use short array syntax [\#135](https://github.com/kevinpapst/kimai2/pull/135) ([simonschaufi](https://github.com/simonschaufi))
- Duration only mode \#131 [\#134](https://github.com/kevinpapst/kimai2/pull/134) ([kevinpapst](https://github.com/kevinpapst))
- added controller to render markdown documentation \#129 [\#132](https://github.com/kevinpapst/kimai2/pull/132) ([kevinpapst](https://github.com/kevinpapst))
- Rounding rules [\#128](https://github.com/kevinpapst/kimai2/pull/128) ([kevinpapst](https://github.com/kevinpapst))
- Secure create-user command [\#127](https://github.com/kevinpapst/kimai2/pull/127) ([simonschaufi](https://github.com/simonschaufi))
- ConfigureFilenames with hash after filename [\#126](https://github.com/kevinpapst/kimai2/pull/126) ([simonschaufi](https://github.com/simonschaufi))
- added webpack-encore for managing frontend assets \#113 [\#122](https://github.com/kevinpapst/kimai2/pull/122) ([kevinpapst](https://github.com/kevinpapst))
- Remove personal mentions in license header [\#119](https://github.com/kevinpapst/kimai2/pull/119) ([simonschaufi](https://github.com/simonschaufi))
- Add github issue and pull request template [\#118](https://github.com/kevinpapst/kimai2/pull/118) ([simonschaufi](https://github.com/simonschaufi))
- Improvements [\#114](https://github.com/kevinpapst/kimai2/pull/114) ([kevinpapst](https://github.com/kevinpapst))
- added first docu on extending kimai with bundles \#106 [\#109](https://github.com/kevinpapst/kimai2/pull/109) ([kevinpapst](https://github.com/kevinpapst))
- added order number to projects \#107 [\#108](https://github.com/kevinpapst/kimai2/pull/108) ([kevinpapst](https://github.com/kevinpapst))
- added short invoice calculator and timesheet invoice template \#104 [\#105](https://github.com/kevinpapst/kimai2/pull/105) ([kevinpapst](https://github.com/kevinpapst))
- added command to import data from kimai v1 \#102 [\#103](https://github.com/kevinpapst/kimai2/pull/103) ([kevinpapst](https://github.com/kevinpapst))
- Error pages \#100 [\#101](https://github.com/kevinpapst/kimai2/pull/101) ([kevinpapst](https://github.com/kevinpapst))
- added basic invoice rendering \#97 [\#99](https://github.com/kevinpapst/kimai2/pull/99) ([kevinpapst](https://github.com/kevinpapst))
- added remember me feature \#53 [\#98](https://github.com/kevinpapst/kimai2/pull/98) ([kevinpapst](https://github.com/kevinpapst))
- code-cleanup: removed unused classes, added role constants, phpcs fixes [\#96](https://github.com/kevinpapst/kimai2/pull/96) ([kevinpapst](https://github.com/kevinpapst))
- load doctrine extensions during kernel bootstrap \#84 [\#92](https://github.com/kevinpapst/kimai2/pull/92) ([kevinpapst](https://github.com/kevinpapst))
- support theme options via user preferences \#89 [\#91](https://github.com/kevinpapst/kimai2/pull/91) ([kevinpapst](https://github.com/kevinpapst))
- added dynamic user preferences \#7 \#9 [\#90](https://github.com/kevinpapst/kimai2/pull/90) ([kevinpapst](https://github.com/kevinpapst))
- added control sidebar \#10 [\#87](https://github.com/kevinpapst/kimai2/pull/87) ([kevinpapst](https://github.com/kevinpapst))
- added english translation \#8 [\#82](https://github.com/kevinpapst/kimai2/pull/82) ([kevinpapst](https://github.com/kevinpapst))
- upgraded to symfony 4 \#74 [\#81](https://github.com/kevinpapst/kimai2/pull/81) ([kevinpapst](https://github.com/kevinpapst))
## [0.1](https://github.com/kevinpapst/kimai2/tree/0.1) (2018-01-10)
**Closed issues:**
- Hide inactive delete user button [\#78](https://github.com/kevinpapst/kimai2/issues/78)
- Delete activity [\#71](https://github.com/kevinpapst/kimai2/issues/71)
- Delete other users timesheet entries [\#70](https://github.com/kevinpapst/kimai2/issues/70)
- Delete Project [\#69](https://github.com/kevinpapst/kimai2/issues/69)
- Delete Customer [\#68](https://github.com/kevinpapst/kimai2/issues/68)
- Delete timesheet entries [\#67](https://github.com/kevinpapst/kimai2/issues/67)
- Add installation docu [\#64](https://github.com/kevinpapst/kimai2/issues/64)
- Disallow login for inactive user [\#57](https://github.com/kevinpapst/kimai2/issues/57)
- Add toolbar to filter user screen [\#56](https://github.com/kevinpapst/kimai2/issues/56)
- Upgrade to latest Avanzu version [\#55](https://github.com/kevinpapst/kimai2/issues/55)
- AdminLTE login screen [\#52](https://github.com/kevinpapst/kimai2/issues/52)
- Add edit Timesheet entry for Teamleads [\#45](https://github.com/kevinpapst/kimai2/issues/45)
- Add Timesheet Voter [\#44](https://github.com/kevinpapst/kimai2/issues/44)
- Developer improvements [\#42](https://github.com/kevinpapst/kimai2/issues/42)
- Base class for repository and query objects [\#40](https://github.com/kevinpapst/kimai2/issues/40)
- Add console command to create user [\#36](https://github.com/kevinpapst/kimai2/issues/36)
- Add basic security Voter [\#34](https://github.com/kevinpapst/kimai2/issues/34)
- Do not show hidden Activities [\#33](https://github.com/kevinpapst/kimai2/issues/33)
- Do not show hidden Projects [\#32](https://github.com/kevinpapst/kimai2/issues/32)
- Add "create timesheet record" form [\#31](https://github.com/kevinpapst/kimai2/issues/31)
- Add filter to Customer admin [\#28](https://github.com/kevinpapst/kimai2/issues/28)
- Do not show hidden Customer [\#27](https://github.com/kevinpapst/kimai2/issues/27)
- Rename Timesheet query class [\#25](https://github.com/kevinpapst/kimai2/issues/25)
- Add "create activity" functionality [\#24](https://github.com/kevinpapst/kimai2/issues/24)
- Add "create project" functionality [\#23](https://github.com/kevinpapst/kimai2/issues/23)
- Add "create customer" functionality [\#22](https://github.com/kevinpapst/kimai2/issues/22)
- Translate dashboard widgets [\#20](https://github.com/kevinpapst/kimai2/issues/20)
- Display user avatar in navbar [\#16](https://github.com/kevinpapst/kimai2/issues/16)
- Add role SUPER\_ADMIN [\#15](https://github.com/kevinpapst/kimai2/issues/15)
- Teamlead can see all user times [\#13](https://github.com/kevinpapst/kimai2/issues/13)
- Add filter to Timesheet \(user\) [\#11](https://github.com/kevinpapst/kimai2/issues/11)
- Add "create user" functionality [\#5](https://github.com/kevinpapst/kimai2/issues/5)
- Edit users role [\#4](https://github.com/kevinpapst/kimai2/issues/4)
- Add filter to Timesheet admin [\#3](https://github.com/kevinpapst/kimai2/issues/3)
- Add filter to Activity admin [\#2](https://github.com/kevinpapst/kimai2/issues/2)
- Add filter to Project admin [\#1](https://github.com/kevinpapst/kimai2/issues/1)
**Merged pull requests:**
- hide inactive delete user button \#78 [\#79](https://github.com/kevinpapst/kimai2/pull/79) ([kevinpapst](https://github.com/kevinpapst))
- added delete customer action \#68 [\#77](https://github.com/kevinpapst/kimai2/pull/77) ([kevinpapst](https://github.com/kevinpapst))
- added delete action for projects \#69 [\#76](https://github.com/kevinpapst/kimai2/pull/76) ([kevinpapst](https://github.com/kevinpapst))
- Delete actions \#71 [\#75](https://github.com/kevinpapst/kimai2/pull/75) ([kevinpapst](https://github.com/kevinpapst))
- added delete timesheet record for admins \#70 [\#73](https://github.com/kevinpapst/kimai2/pull/73) ([kevinpapst](https://github.com/kevinpapst))
- added delete timesheet records action for users \#67 [\#72](https://github.com/kevinpapst/kimai2/pull/72) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar to user screen \#56 [\#66](https://github.com/kevinpapst/kimai2/pull/66) ([kevinpapst](https://github.com/kevinpapst))
- document installation options \#64 [\#65](https://github.com/kevinpapst/kimai2/pull/65) ([kevinpapst](https://github.com/kevinpapst))
- update avanzu admin bundle \#55 [\#63](https://github.com/kevinpapst/kimai2/pull/63) ([kevinpapst](https://github.com/kevinpapst))
- prevent inactive user from login \#57 [\#61](https://github.com/kevinpapst/kimai2/pull/61) ([kevinpapst](https://github.com/kevinpapst))
- handle hidden customer \#27 [\#60](https://github.com/kevinpapst/kimai2/pull/60) ([kevinpapst](https://github.com/kevinpapst))
- handle hidden projects \#32 [\#59](https://github.com/kevinpapst/kimai2/pull/59) ([kevinpapst](https://github.com/kevinpapst))
- Handle hidden activities \#33 [\#58](https://github.com/kevinpapst/kimai2/pull/58) ([kevinpapst](https://github.com/kevinpapst))
- using the AdminLTE login screen \#52 [\#54](https://github.com/kevinpapst/kimai2/pull/54) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar for activity screen \#2 [\#51](https://github.com/kevinpapst/kimai2/pull/51) ([kevinpapst](https://github.com/kevinpapst))
- Added toolbar to project screen \#1 [\#50](https://github.com/kevinpapst/kimai2/pull/50) ([kevinpapst](https://github.com/kevinpapst))
- added toolbar to customer screen \#28 [\#49](https://github.com/kevinpapst/kimai2/pull/49) ([kevinpapst](https://github.com/kevinpapst))
- added form to edit timesheet entries for all user \#45 [\#48](https://github.com/kevinpapst/kimai2/pull/48) ([kevinpapst](https://github.com/kevinpapst))
- Create timesheet for User \#31 [\#47](https://github.com/kevinpapst/kimai2/pull/47) ([kevinpapst](https://github.com/kevinpapst))
- added timesheet voter \#44 [\#46](https://github.com/kevinpapst/kimai2/pull/46) ([kevinpapst](https://github.com/kevinpapst))
- Developer cleanup \#42 [\#43](https://github.com/kevinpapst/kimai2/pull/43) ([kevinpapst](https://github.com/kevinpapst))
- Repository cleanup [\#41](https://github.com/kevinpapst/kimai2/pull/41) ([kevinpapst](https://github.com/kevinpapst))
- Added voter for customer, project and activity [\#39](https://github.com/kevinpapst/kimai2/pull/39) ([kevinpapst](https://github.com/kevinpapst))
- added create user console command [\#38](https://github.com/kevinpapst/kimai2/pull/38) ([kevinpapst](https://github.com/kevinpapst))
- added "create user" functionality [\#37](https://github.com/kevinpapst/kimai2/pull/37) ([kevinpapst](https://github.com/kevinpapst))
- Added "create activity" form [\#35](https://github.com/kevinpapst/kimai2/pull/35) ([kevinpapst](https://github.com/kevinpapst))
- Added create project functionality [\#30](https://github.com/kevinpapst/kimai2/pull/30) ([kevinpapst](https://github.com/kevinpapst))
- Rename TimesheetQuery class [\#29](https://github.com/kevinpapst/kimai2/pull/29) ([kevinpapst](https://github.com/kevinpapst))
- Add customer functionality [\#26](https://github.com/kevinpapst/kimai2/pull/26) ([kevinpapst](https://github.com/kevinpapst))
- Dashboard widgets [\#21](https://github.com/kevinpapst/kimai2/pull/21) ([kevinpapst](https://github.com/kevinpapst))
- Added form to edit user roles [\#18](https://github.com/kevinpapst/kimai2/pull/18) ([kevinpapst](https://github.com/kevinpapst))
- added role ROLE\_SUPER\_ADMIN [\#17](https://github.com/kevinpapst/kimai2/pull/17) ([kevinpapst](https://github.com/kevinpapst))
- allow TEAMLEAD to see user times [\#14](https://github.com/kevinpapst/kimai2/pull/14) ([kevinpapst](https://github.com/kevinpapst))
- Timesheet toolbar [\#12](https://github.com/kevinpapst/kimai2/pull/12) ([kevinpapst](https://github.com/kevinpapst))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

View File

@@ -1,20 +1,25 @@
Contributing
============
# Contributing
The Kimai application is an open source project. Contributions made by
the community are welcome. Send us your ideas, code reviews, pull requests and
feature requests to help us improve this project.
Kimai is an open source project, contributions made by the community are welcome.
Send us your ideas, code reviews, pull requests and feature requests to help us improve this project.
Web Assets Management
---------------------
## Pull request rules
This project manages its web assets in a special way to allow them to work
without configuring any option, installing any tool or executing any command.
If your contribution changes CSS styles or JavaScript code in any way, make
sure to regenerate the `web/css/app.css` and `web/js/app.js` files. To do so,
uncomment the Assetic blocks in the `app/Resources/views/base.html.twig` and
execute the following command:
- We use PSR-2 with some additional code-style checks (see our [php-cs-fixer config](.php_cs.dist)). You can run `bin/console kimai:phpcs` to check and `bin/console kimai:phpcs --fix` to fix violations.
- Add PHPUnit tests for your changes, verify everything still works and execute our test-suites `bin/console kimai:test-unit` and `bin/console kimai:test-integration`.
- If you contribute new files, please add them with the file-header template from below (our chode-style fixer can do that for you).
- With sending in a PR, you accept that your contributions/code will be published under MIT license (see the [LICENSE](LICENSE) file as well).
- If one of the PR checks fails, please fix them before asking us for a review.
```bash
$ php bin/console assetic:dump --no-debug
Further documentation can be found in the [developer documentation](var/docs/developers.md).
### File-header template
```
/*
* 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.
*/
```

View File

@@ -1,4 +1,4 @@
Copyright (c) 2016 Kevin Papst
Copyright (c) 2017-2018 Kevin Papst
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

177
README.md
View File

@@ -1,65 +1,74 @@
# Kimai v2 - Time Tracking
Kimai v2 - the reloaded open source Time-Tracking application.
Kimai v2 - the open source time-tracking application with a mobile-first approach, read more at the [official website](http://v2.kimai.org).
[![Build Status](https://travis-ci.org/kevinpapst/kimai2.svg?branch=master)](https://travis-ci.org/kevinpapst/kimai2)
[![Travis Status](https://travis-ci.org/kevinpapst/kimai2.svg?branch=master)](https://travis-ci.org/kevinpapst/kimai2)
[![Code Quality](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/?branch=master)
[![Scrutinizer Status](https://scrutinizer-ci.com/g/kevinpapst/kimai2/badges/build.png?b=master)](https://scrutinizer-ci.com/g/kevinpapst/kimai2/build-status/master)
## Introduction
This is (or will be in the future, currently a lot of features are still missing) the reloaded version of the open source time-tracking application [Kimai](http://www.kimai.org).
This is the reloaded version of the open source timetracker Kimai.
Right now its in an early development phase, its usable but some advanced features from Kimai v1 are missing by now.
It is based on the following PHP components:
- [Symfony Framework 3.4](https://github.com/symfony/symfony)
- [AdminThemeBundle](https://github.com/avanzu/AdminThemeBundle/) (based on [AdminLTE](https://github.com/almasaeed2010/AdminLTE/))
- [Doctrine](https://github.com/doctrine/)
- Bower
Kimai v2 has nothing in common with its predecessor [Kimai v1](http://www.kimai.org) besides the basic ideas of time-tracking and the current development team.
It is based on a lot of great frameworks. Special thanks to [Symfony v4](https://github.com/symfony/symfony), [Doctrine](https://github.com/doctrine/),
[AdminThemeBundle](https://github.com/avanzu/AdminThemeBundle/) (based on [AdminLTE](https://github.com/almasaeed2010/AdminLTE/)).
## Requirements
### Requirements
- PHP 7 or higher
- One PHP extension of PDO-SQLite and/or PDO-MySQL enabled
- and the [usual Symfony application requirements](http://symfony.com/doc/current/reference/requirements.html)
- PHP 7.1.3 or higher
- One PHP extension of PDO-SQLite or PDO-MySQL enabled (it might work with PostgreSQL and Oracle as well, but that wasn't tested and is not officially supported)
- the [usual Symfony application requirements](http://symfony.com/doc/current/reference/requirements.html)
- Kimai needs to be installed in the root directory of a domain or you need to [recompile the frontend assets](var/docs/developers.md)
If unsure about meeting these requirements, download the demo application and
browse to the <http://localhost:8000/config.php> script to get more detailed information.
## Documentation & Roadmap
Looking for more information about using Kimai? Check out our more detailed [documentation](var/docs/).
You can see our development roadmap for the future in the [Milestones](milestones/) sections,
current work is organized in the [Project](projects/) planning boards.
Our roadmap is open for changes and input from the community, please [sent us](issues/) your ideas and questions.
## Installation
First, install Git and [Composer](https://getcomposer.org/doc/00-intro.md)
if you haven't already. Then, clone this repo and execute this command in the cloned directory:
First, install Git and [Composer](https://getcomposer.org/doc/00-intro.md) if you haven't already. Then clone this repo:
```bash
$ git clone https://github.com/kevinpapst/kimai2.git
$ cd kimai2/
git clone https://github.com/kevinpapst/kimai2.git
cd kimai2/
```
Lets prepare the environment by installing all dependencies. You will be asked for your application parameter,
like the database connection afterwards (if you don't have a [app/config/parameters.yml](blob/master/app/config/parameters.yml.dist) yet):
The next steps depend in which environment you want to use Kimai, you can choose between development or production mode.
### Installation (development)
Lets prepare the environment by installing all dependencies:
```bash
$ composer install
composer install
```
The next command will create the database, the schema and install all web assets:
```bash
$ bin/console kimai:install --relative
The default installation uses a SQLite database, so there is no need to create a database for your first tests.
Our default settings will work out-of-the-box, but you might want to adjust the `.env` values to your needs.
You can configure your database through your environment (e.g. Webserver, Cloud-Provider) or in your `.env` file:
```
DATABASE_PREFIX=kimai2_
DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/kimai.sqlite
APP_ENV=dev
APP_SECRET=some_random_secret_string_for_your_installation
```
### Installation (live)
All thats left to do is to create your first user:
The next command will create the database and the schema:
```bash
$ bin/console kimai:create-user admin admin@example.com password en ROLE_SUPER_ADMIN
bin/console doctrine:database:create
bin/console doctrine:schema:create
```
For available roles, please refer to [the user documentation](app/Resources/docs/users.md).
### Installation (development / demo)
Lets boostrap your environment by executing this commands (which is only available in dev environment):
Lets bootstrap your environment by executing this commands (which is only available in dev environment):
```bash
$ bin/console kimai:dev:reset
bin/console kimai:reset-dev
```
You just imported demo data, to test the application in its full beauty and with several different user accounts and permission sets.
@@ -79,36 +88,110 @@ Demo data can always be deleted by dropping the schema and re-creating it.
ATTENTION - this will erase all your data:
```bash
$ bin/console doctrine:schema:drop --force
$ bin/console doctrine:schema:create
bin/console doctrine:schema:drop --force
bin/console doctrine:schema:create
```
The `kimai:dev:reset` command can always be executed later on to reset your dev database and cache. I use it very frequently.
## Usage
The `kimai:reset-dev` command can always be executed later on to reset your dev database and cache.
There is no need to configure a virtual host in your web server to access the application for testing.
Just use the built-in web server for your first tests:
```bash
$ APP_FRONT_CONTROLLER=app.php bin/console server:run
bin/console server:run
```
This command will start a web server for Kimai. Now you can access the application in your browser at <http://127.0.0.1:8000/>.
This command will start a web server for Kimai. Now you can access the application in your browser at <http://127.0.0.1:8000/>.
You can stop the built-in web server by pressing `Ctrl + C` while you're in the terminal.
To re-generate the frontend assets ([more information here](var/docs/developers.md)), execute:
```bash
yarn install
npm run prod
```
### Installation (production)
Lets prepare the environment by installing all dependencies:
```bash
composer install --no-dev
```
Make sure the [directories are read and writable by your webserver](https://symfony.com/doc/current/setup/file_permissions.html):
```bash
chown -R www-data var/
chmod -R 777 var/
```
The database to use is up to you, but we would not recommend using the default SQLite database for production usage.
Please create your database and configure the connection string in your environment, e.g. with the `.env` file:
```
APP_ENV=prod
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
APP_SECRET=insert_a_random_secret_string_for_production
```
Create the database schemas and warm up the cache (as webserver user):
```bash
bin/console doctrine:schema:create
sudo -u www-data bin/console cache:warmup --env=prod
```
Create your first user with the following command. You will be asked to enter a password afterwards.
```bash
bin/console kimai:create-user username admin@example.com ROLE_SUPER_ADMIN
```
_Tip: You can skip the "create user" step, if you are going to import data from Kimai v1._
For available roles, please refer to the [user documentation](var/docs/users.md).
> **NOTE**
>
> If you want to use a fully-featured web server (like Nginx or Apache) to run
> Kimai, configure it to point at the `web/` directory of the project.
> Kimai, configure it to point at the `public/` directory of the project.
> For more details, see:
> http://symfony.com/doc/current/cookbook/configuration/web_server_configuration.html
## Troubleshooting
That's it, you can start time-tracking :-)
Cannot see any assets (like images) and/or missing styles? Try executing:
### Importing data from Kimai v1
Before importing your data from a Kimai v1 installation, please read the following carefully:
- Data from the existing v1 installation is only read and will never be changed
- Data can only be imported from a Kimai installation with at least `v1.0.1` and database revision `1388` (check your `configuration` table)
- Kimai v1 has support for activities without project assignment, which Kimai v2 doesn't support. Unattached activities will be created for every project that has a linked activity in any of the imported timesheet records
- Rates and fixed-rates are handled in a completely different way and for now only the timesheet record total amounts are imported
- Customers cannot login and no user accounts will be created for them
- The customers country has to be manually assigned afterwards, as there is no field in Kimai v1 for that
- You have to supply the default password that is used for every imported user, as their password will be resetted
- Data that was deleted in Kimai v1 (user, customer, projects, activities) will be imported and set to `invisible` (if you don't want that, you have to delete all entries that have the value `1` in the `trash` column before importing)
A possible full command for import:
```bash
$ php bin/console assets:install --symlink
bin/console kimai:import-v1 "mysql://user:password@127.0.0.1:3306/database?charset=utf8" "db_prefix" "password" "country"
```
It is recommended to test the import in a fresh database. You can test your import as often as you like and fix possible problems in your installation.
A sample command could look like that:
```bash
bin/console doctrine:schema:drop --force && bin/console doctrine:schema:create && bin/console kimai:import-v1 "mysql://kimai:test@127.0.0.1:3306/kimai?charset=latin1" "kimai_" "test123" "de"
```
That will drop the configured Kimai v2 database schema and re-create it, before importing the data from the `mysql` database at `127.0.0.1` on port `3306` authenticating the user `kimai` with the password `test` for import.
The connection will use the charset `latin1` and the default table prefix `kimai_` for reading data. Imported users can login with the password `test123` and all customer will have the country `de` assigned.
## Extensions for Kimai 2
As Kimai 2 was built on top of Symfony, it can be extended like every other Symfony application.
We call these extensions bundles, but you might also know them as add-ons, extensions or plugins.
All available Kimai 2 bundles can be found at the [Kimai recipes](https://github.com/kimai/recipes) repository.
## Developer
If you want to develop for Kimai 2 please read the following documentation:
- an example on how to extend Kimai 2 can be found in this [GitHub repository](https://github.com/kevinpapst/kimai2-invoice)
- the [developer documentation](var/docs/developers.md) is available both on GitHub and your local installation

View File

@@ -1,26 +0,0 @@
{
"name": "Kimai v2",
"description": "The reloaded Kimai Time-tracking application",
"keywords": [
"php",
"kimai"
],
"website": "https://www.kimai.org.com/",
"repository": "https://github.com/kevinpapst/kimai2",
"logo": "",
"success_url": "/",
"scripts": {
"postdeploy": "php bin/console doctrine:schema:create && php bin/console doctrine:fixtures:load -n"
},
"env": {
"SYMFONY_ENV": "prod",
"SYMFONY_SECRET": {
"description": "Extra entropy for %kernel.secret%; used for CSRF tokens, cookies and signed URLs.",
"generator": "secret"
}
},
"addons": [
"heroku-postgresql"
],
"image": "heroku/php"
}

View File

@@ -1,7 +0,0 @@
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>

View File

@@ -1,21 +0,0 @@
<?php
/*
* This file is part of the Kimai package.
*
* (c) Kevin Papst <kevin@kevinpapst.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
/**
* Class AppCache
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
class AppCache extends HttpCache
{
}

View File

@@ -1,71 +0,0 @@
<?php
/*
* This file is part of the Kimai package.
*
* (c) Kevin Papst <kevin@kevinpapst.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
/**
* Class AppKernel
*
* @author Kevin Papst <kevin@kevinpapst.de>
*/
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new Avanzu\AdminThemeBundle\AvanzuAdminThemeBundle(),
new AppBundle\AppBundle(),
new TimesheetBundle\TimesheetBundle(),
];
// Bundles only used for development or unit and functional tests
if (in_array($this->getEnvironment(), ['dev', 'test'])) {
//$bundles[] = new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle();
$bundles[] = new Symfony\Bundle\AsseticBundle\AsseticBundle();
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
$bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle();
}
return $bundles;
}
public function getRootDir()
{
return __DIR__;
}
public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
}
public function getLogDir()
{
return dirname(__DIR__).'/var/logs';
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
}

View File

@@ -1,12 +0,0 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{{ asset('theme/bootstrap/css/bootstrap.min.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
{#<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.min.css">#}
<link rel="stylesheet" href="{{ asset('theme/dist/css/AdminLTE.min.css') }}">
<link rel="stylesheet" href="{{ asset("theme/dist/css/skins/" ~ avanzu_admin_context.skin|default('skin-blue-light') ~ ".min.css") }}">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->

View File

@@ -1,28 +0,0 @@
{#
This template is used to render any error different from 403, 404 and 500.
This is the simplest way to customize error pages in Symfony applications.
In case you need it, you can also hook into the internal exception handling
made by Symfony. This allows you to perform advanced tasks and even recover
your application from some errors.
See http://symfony.com/doc/current/cookbook/controller/error_pages.html
#}
{% extends 'base.html.twig' %}
{% block body_id 'error' %}
{% block main %}
<h1 class="text-danger">{{ 'http_error.name'|trans({ '%status_code%': status_code }) }}</h1>
<p class="lead">
{{ 'http_error.description'|trans({ '%status_code%': status_code }) }}
</p>
<p>
{{ 'http_error.suggestion'|trans({ '%url%': path('homepage') })|raw }}
</p>
{% endblock %}
{% block sidebar %}
{{ parent() }}
{% endblock %}

View File

@@ -1,28 +0,0 @@
{#
This template is used to render errors of type HTTP 403 (Forbidden)
This is the simplest way to customize error pages in Symfony applications.
In case you need it, you can also hook into the internal exception handling
made by Symfony. This allows you to perform advanced tasks and even recover
your application from some errors.
See http://symfony.com/doc/current/cookbook/controller/error_pages.html
#}
{% extends 'base.html.twig' %}
{% block body_id 'error' %}
{% block main %}
<h1 class="text-danger"><i class="fa fa-unlock-alt"></i> {{ 'http_error.name'|trans({ '%status_code%': 403 }) }}</h1>
<p class="lead">
{{ 'http_error_403.description'|trans }}
</p>
<p>
{{ 'http_error_403.suggestion'|trans }}
</p>
{% endblock %}
{% block sidebar %}
{{ parent() }}
{% endblock %}

View File

@@ -1,28 +0,0 @@
{#
This template is used to render errors of type HTTP 404 (Not Found)
This is the simplest way to customize error pages in Symfony applications.
In case you need it, you can also hook into the internal exception handling
made by Symfony. This allows you to perform advanced tasks and even recover
your application from some errors.
See http://symfony.com/doc/current/cookbook/controller/error_pages.html
#}
{% extends 'base.html.twig' %}
{% block body_id 'error' %}
{% block main %}
<h1 class="text-danger">{{ 'http_error.name'|trans({ '%status_code%': 404 }) }}</h1>
<p class="lead">
{{ 'http_error_404.description'|trans }}
</p>
<p>
{{ 'http_error_404.suggestion'|trans({ '%url%': path('homepage') })|raw }}
</p>
{% endblock %}
{% block sidebar %}
{{ parent() }}
{% endblock %}

View File

@@ -1,14 +0,0 @@
# Users
There are multiple pre-defined roles in Kimai, which define the ACLs. A user can only inherit one role, where the roles extend each user.
## Roles
| Role name | extends | Gives permission for |
|---|---|---|
| ROLE_CUSTOMER | - | Currently has no permissions, but was reserved for future functionality |
| ROLE_USER | ROLE_CUSTOMER | Time-tracking |
| ROLE_TEAMLEAD | ROLE_USER | All of the above, plus: editing other users timesheets |
| ROLE_ADMIN | ROLE_TEAMLEAD | All of the above, plus: editing customers, editing projects, editing activities |
| ROLE_SUPER_ADMIN | ROLE_ADMIN | All of the above, plus: editing users |

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file date="2016-10-19T21:46:45Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<trans-unit id="Toggle navigation">
<source>Toggle navigation</source>
<target>Ansicht der Seitenleiste umschalten</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file date="2016-10-19T21:46:45Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<trans-unit id="access.denied">
<source>access.denied</source>
<target>Der Zugriff wurde verweigert</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file date="2016-10-19T21:46:45Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<trans-unit id="timesheet.stop.success">
<source>timesheet.stop.success</source>
<target>Zeitmessung wurde gestoppt</target>
</trans-unit>
<trans-unit id="timesheet.stop.error">
<source>timesheet.stop.error</source>
<target>Zeitmessung konnte nicht gestoppt werden: %reason%</target>
</trans-unit>
<trans-unit id="timesheet.start.success">
<source>timesheet.start.success</source>
<target>Zeitmessung wurde gestartet</target>
</trans-unit>
<trans-unit id="timesheet.start.error">
<source>timesheet.start.error</source>
<target>Zeitmessung konnte nicht gestartet werden: %reason%</target>
</trans-unit>
<trans-unit id="action.updated_successfully">
<source>action.updated_successfully</source>
<target>Änderungen erfolgreich gespeichert</target>
</trans-unit>
<trans-unit id="action.deleted_successfully">
<source>action.deleted_successfully</source>
<target>Eintrag wurde erfolgreich gelöscht</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,712 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file date="2016-10-19T21:46:45Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<!--
Global template keys
-->
<trans-unit id="browser.title">
<source>browser.title</source>
<target>Kimai - Time Tracking</target>
</trans-unit>
<trans-unit id="yes">
<source>yes</source>
<target>Ja</target>
</trans-unit>
<trans-unit id="no">
<source>no</source>
<target>Nein</target>
</trans-unit>
<trans-unit id="subtitle.amount">
<source>subtitle.amount</source>
<target> (insgesamt %count%)</target>
</trans-unit>
<trans-unit id="This is a mandatory field">
<source>This is a mandatory field</source>
<target>Pflichtfeld</target>
</trans-unit>
<trans-unit id="create">
<source>create</source>
<target>Erstellen</target>
</trans-unit>
<trans-unit id="confirm.delete">
<source>confirm.delete</source>
<target>Wollen Sie das wirklich löschen?</target>
</trans-unit>
<trans-unit id="confirm.delete_message">
<source>confirm.delete_message</source>
<target>Sie müssen das Löschen erneut bestätigen, da verknüpfte Objekte existieren welche ebenfalls mit gelöscht werden.</target>
</trans-unit>
<!--
Login / Security
-->
<trans-unit id="security.title.login">
<source>security.title.login</source>
<target>Anmelden</target>
</trans-unit>
<trans-unit id="security.label.username">
<source>security.label.username</source>
<target>Benutzername</target>
</trans-unit>
<trans-unit id="security.label.password">
<source>security.label.password</source>
<target>Passwort</target>
</trans-unit>
<trans-unit id="security.label.password_repeat">
<source>security.label.password_repeat</source>
<target>Passwort wiederholen</target>
</trans-unit>
<trans-unit id="security.action.sign_in">
<source>security.action.sign_in</source>
<target>Los geht's</target>
</trans-unit>
<trans-unit id="label.logout">
<source>label.logout</source>
<target>Abmelden</target>
</trans-unit>
<trans-unit id="label.user_profile">
<source>label.user_profile</source>
<target>Mein Profil</target>
</trans-unit>
<!--
Menu / Navbar items
-->
<trans-unit id="menu.homepage">
<source>menu.homepage</source>
<target>Dashboard</target>
</trans-unit>
<trans-unit id="menu.admin">
<source>menu.admin</source>
<target>Administration</target>
</trans-unit>
<trans-unit id="menu.logout">
<source>menu.logout</source>
<target>Abmelden</target>
</trans-unit>
<trans-unit id="menu.timesheet">
<source>menu.timesheet</source>
<target>Zeiterfassung</target>
</trans-unit>
<trans-unit id="menu.admin_timesheet">
<source>menu.admin_timesheet</source>
<target>Mitarbeiter Zeiten</target>
</trans-unit>
<trans-unit id="menu.admin_customer">
<source>menu.admin_customer</source>
<target>Kunden</target>
</trans-unit>
<trans-unit id="menu.admin_project">
<source>menu.admin_project</source>
<target>Projekte</target>
</trans-unit>
<trans-unit id="menu.admin_activity">
<source>menu.admin_activity</source>
<target>Aktivitäten</target>
</trans-unit>
<trans-unit id="menu.admin_user">
<source>menu.admin_user</source>
<target>Benutzer</target>
</trans-unit>
<!--
Footer
-->
<trans-unit id="footer.license">
<source>footer.license</source>
<target>Alle Rechte vorbehalten.</target>
</trans-unit>
<!--
Error templates
-->
<trans-unit id="http_error.name">
<source>http_error.name</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error.description">
<source>http_error.description</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error.suggestion">
<source>http_error.suggestion</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_403.description">
<source>http_error_403.description</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_403.suggestion">
<source>http_error_403.suggestion</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_404.description">
<source>http_error_404.description</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_404.suggestion">
<source>http_error_404.suggestion</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_405.description">
<source>http_error_405.description</source>
<target>Error</target>
</trans-unit>
<trans-unit id="http_error_405.suggestion">
<source>http_error_405.suggestion</source>
<target>Error</target>
</trans-unit>
<trans-unit id="error.no_entries_found">
<source>error.no_entries_found</source>
<target>Keine Einträge vorhanden</target>
</trans-unit>
<!--
General labels
-->
<trans-unit id="label.date">
<source>label.date</source>
<target>Datum</target>
</trans-unit>
<trans-unit id="label.starttime">
<source>label.starttime</source>
<target>Begin</target>
</trans-unit>
<trans-unit id="label.endtime">
<source>label.endtime</source>
<target>Ende</target>
</trans-unit>
<trans-unit id="label.duration">
<source>label.duration</source>
<target>Dauer</target>
</trans-unit>
<trans-unit id="label.username">
<source>label.username</source>
<target>Benutzer</target>
</trans-unit>
<trans-unit id="label.description">
<source>label.description</source>
<target>Beschreibung</target>
</trans-unit>
<trans-unit id="label.name">
<source>label.name</source>
<target>Name</target>
</trans-unit>
<trans-unit id="label.comment">
<source>label.comment</source>
<target>Kommentar</target>
</trans-unit>
<trans-unit id="label.id">
<source>label.id</source>
<target>ID</target>
</trans-unit>
<trans-unit id="label.visible">
<source>label.visible</source>
<target>Sichtbar</target>
</trans-unit>
<trans-unit id="label.budget">
<source>label.budget</source>
<target>Budget</target>
</trans-unit>
<trans-unit id="label.activity">
<source>label.activity</source>
<target>Aktivität</target>
</trans-unit>
<trans-unit id="label.project">
<source>label.project</source>
<target>Projekt</target>
</trans-unit>
<trans-unit id="label.hourly_rate">
<source>label.hourly_rate</source>
<target>Stundenlohn</target>
</trans-unit>
<trans-unit id="label.hours">
<source>label.hours</source>
<target>Stunden</target>
</trans-unit>
<trans-unit id="label.rate">
<source>label.rate</source>
<target>Lohn</target>
</trans-unit>
<trans-unit id="label.language">
<source>label.language</source>
<target>Sprache</target>
</trans-unit>
<trans-unit id="label.customer">
<source>label.customer</source>
<target>Kunde</target>
</trans-unit>
<trans-unit id="label.email">
<source>label.email</source>
<target>Email</target>
</trans-unit>
<!--
Buttons & Actions
-->
<trans-unit id="label.actions">
<source>label.actions</source>
<target>Aktionen</target>
</trans-unit>
<trans-unit id="action.edit">
<source>action.edit</source>
<target>Bearbeiten</target>
</trans-unit>
<trans-unit id="action.delete">
<source>action.delete</source>
<target>Löschen</target>
</trans-unit>
<trans-unit id="action.save">
<source>action.save</source>
<target>Speichern</target>
</trans-unit>
<trans-unit id="action.back">
<source>action.back</source>
<target>Zurück</target>
</trans-unit>
<!--
Dashboard
-->
<trans-unit id="dashboard.title">
<source>dashboard.title</source>
<target>Dashboard</target>
</trans-unit>
<trans-unit id="dashboard.subtitle">
<source>dashboard.subtitle</source>
<target>Willkommen!</target>
</trans-unit>
<trans-unit id="dashboard.you">
<source>dashboard.you</source>
<target>Deine Statistiken</target>
</trans-unit>
<trans-unit id="dashboard.all">
<source>dashboard.all</source>
<target>Alle Benutzer</target>
</trans-unit>
<trans-unit id="dashboard.admin">
<source>dashboard.admin</source>
<target>Administrator</target>
</trans-unit>
<!--
Widgets
-->
<trans-unit id="more.info.link">
<source>more.info.link</source>
<target>Mehr Infos</target>
</trans-unit>
<trans-unit id="badge.visible">
<source>badge.visible</source>
<target>Ja</target>
</trans-unit>
<trans-unit id="badge.invisible">
<source>badge.invisible</source>
<target>Nein</target>
</trans-unit>
<trans-unit id="label.toggle_dropdown">
<source>label.toggle_dropdown</source>
<target>Menü anzeigen</target>
</trans-unit>
<!--
Timesheet
-->
<trans-unit id="timesheet.title">
<source>timesheet.title</source>
<target>Zeiterfassung</target>
</trans-unit>
<trans-unit id="timesheet.subtitle">
<source>timesheet.subtitle</source>
<target>Verwalten Sie Ihre Zeiteinträge</target>
</trans-unit>
<trans-unit id="timesheet.edit">
<source>timesheet.edit</source>
<target>Eintrag bearbeiten</target>
</trans-unit>
<trans-unit id="label.begin">
<source>label.begin</source>
<target>Von</target>
</trans-unit>
<trans-unit id="label.end">
<source>label.end</source>
<target>Bis</target>
</trans-unit>
<!--
User profile
-->
<trans-unit id="profile.title">
<source>profile.title</source>
<target>Benutzerprofil</target>
</trans-unit>
<trans-unit id="profile.subtitle">
<source>profile.subtitle</source>
<target>Verwalte Deine Einstellungen</target>
</trans-unit>
<trans-unit id="profile.about_me">
<source>profile.about_me</source>
<target>Über mich</target>
</trans-unit>
<trans-unit id="profile.first_entry">
<source>profile.first_entry</source>
<target>Arbeitet seit</target>
</trans-unit>
<trans-unit id="profile.tab_monthly">
<source>profile.tab_monthly</source>
<target>Jahresstatistik</target>
</trans-unit>
<trans-unit id="profile.settings">
<source>profile.settings</source>
<target>Einstellungen</target>
</trans-unit>
<trans-unit id="profile.password">
<source>profile.password</source>
<target>Passwort</target>
</trans-unit>
<trans-unit id="profile.roles">
<source>profile.roles</source>
<target>Rollen</target>
</trans-unit>
<!--
Admin: Timesheet
-->
<trans-unit id="admin_timesheet.title">
<source>admin_timesheet.title</source>
<target>Mitarbeiter Zeiterfassung</target>
</trans-unit>
<trans-unit id="admin_timesheet.subtitle">
<source>admin_timesheet.subtitle</source>
<target>Zeiten aller Benutzer</target>
</trans-unit>
<!--
Admin: Projects
-->
<trans-unit id="admin_project.title">
<source>admin_project.title</source>
<target>Projekte</target>
</trans-unit>
<trans-unit id="admin_project.subtitle">
<source>admin_project.subtitle</source>
<target>Ein Projekt fasst Tätigkeiten für jeweils einen Kunden in einer Gruppe zusammen</target>
</trans-unit>
<trans-unit id="admin_project.delete_confirm">
<source>admin_project.delete_confirm</source>
<target>Momentan existieren für das Projekt %project% des Kunden %customer% insgesamt %activities% Aktivitäten und %records% Zeiteinträge, welche sich auf eine Gesamtdauer von %duration% belaufen. Diese Aktivitäten und Zeiteinträge werden ebenfalls mit gelöscht!</target>
</trans-unit>
<!--
Admin: Activity
-->
<trans-unit id="admin_activity.title">
<source>admin_activity.title</source>
<target>Aktivitäten</target>
</trans-unit>
<trans-unit id="admin_activity.subtitle">
<source>admin_activity.subtitle</source>
<target>Aufgaben die zur Zeiterfassung genutzt werden können</target>
</trans-unit>
<trans-unit id="admin_activity.delete_confirm">
<source>admin_activity.delete_confirm</source>
<target>Momentan existieren für die Aktivität %activity% im Projekt %project% für den Kunden %customer% insgesamt %records% Zeiteinträge, welche sich auf eine Gesamtdauer von %duration% belaufen. Diese Zeiteinträge werden ebenfalls mit gelöscht!</target>
</trans-unit>
<!--
Admin: Customer
-->
<trans-unit id="admin_customer.title">
<source>admin_customer.title</source>
<target>Kunden</target>
</trans-unit>
<trans-unit id="admin_customer.subtitle">
<source>admin_customer.subtitle</source>
<target>Ihre Kunden stellen die Basis dar, auf der Sie Projekte und Tätigkeiten anlegen können</target>
</trans-unit>
<trans-unit id="label.company">
<source>label.company</source>
<target>Unternehmensbezeichnung</target>
</trans-unit>
<trans-unit id="label.vat">
<source>label.vat</source>
<target>Umsatzsteuer</target>
</trans-unit>
<trans-unit id="label.contact">
<source>label.contact</source>
<target>Kontakt</target>
</trans-unit>
<trans-unit id="label.address">
<source>label.address</source>
<target>Adresse</target>
</trans-unit>
<trans-unit id="label.country">
<source>label.country</source>
<target>Land</target>
</trans-unit>
<trans-unit id="label.phone">
<source>label.phone</source>
<target>Telefon</target>
</trans-unit>
<trans-unit id="label.fax">
<source>label.fax</source>
<target>Fax</target>
</trans-unit>
<trans-unit id="label.mobile">
<source>label.mobile</source>
<target>Handy</target>
</trans-unit>
<trans-unit id="label.homepage">
<source>label.homepage</source>
<target>Homepage</target>
</trans-unit>
<trans-unit id="label.timezone">
<source>label.timezone</source>
<target>Zeitzone</target>
</trans-unit>
<trans-unit id="label.currency">
<source>label.currency</source>
<target>Währung</target>
</trans-unit>
<trans-unit id="admin_customer.delete_confirm">
<source>admin_customer.delete_confirm</source>
<target>Momentan existieren für den Kunden %customer% insgesamt %project% Projekte mit %activity% Aktivitäten, die sich in %records% Zeiteinträgen auf eine Gesamtdauer von %duration% belaufen. Diese Projekte, Aktivitäten und Zeiteinträge werden ebenfalls mit gelöscht!</target>
</trans-unit>
<!--
Admin: User
-->
<trans-unit id="admin_user.title">
<source>admin_user.title</source>
<target>Benutzer</target>
</trans-unit>
<trans-unit id="admin_user.subtitle">
<source>admin_user.subtitle</source>
<target>Alle registrierten Benutzer der Zeitverwaltung</target>
</trans-unit>
<trans-unit id="label.alias">
<source>label.alias</source>
<target>Name</target>
</trans-unit>
<trans-unit id="label.title">
<source>label.title</source>
<target>Titel</target>
</trans-unit>
<trans-unit id="label.avatar">
<source>label.avatar</source>
<target>Profilbild</target>
</trans-unit>
<trans-unit id="label.active">
<source>label.active</source>
<target>Aktiv</target>
</trans-unit>
<trans-unit id="label.roles">
<source>label.roles</source>
<target>Rolle</target>
</trans-unit>
<!--
ROLES
-->
<trans-unit id="ROLE_SUPER_ADMIN">
<source>ROLE_SUPER_ADMIN</source>
<target>System-Admin</target>
</trans-unit>
<trans-unit id="ROLE_ADMIN">
<source>ROLE_ADMIN</source>
<target>Administrator</target>
</trans-unit>
<trans-unit id="ROLE_TEAMLEAD">
<source>ROLE_TEAMLEAD</source>
<target>Teamleiter</target>
</trans-unit>
<trans-unit id="ROLE_USER">
<source>ROLE_USER</source>
<target>Benutzer</target>
</trans-unit>
<trans-unit id="ROLE_CUSTOMER">
<source>ROLE_CUSTOMER</source>
<target>Kunde</target>
</trans-unit>
<!--
Statistics
-->
<trans-unit id="stats.durationThisMonth">
<source>stats.durationThisMonth</source>
<target>Arbeitszeit diesen Monat</target>
</trans-unit>
<trans-unit id="stats.amountThisMonth">
<source>stats.amountThisMonth</source>
<target>Umsatz diesen Monat</target>
</trans-unit>
<trans-unit id="stats.durationTotal">
<source>stats.durationTotal</source>
<target>Arbeitszeit total</target>
</trans-unit>
<trans-unit id="stats.amountTotal">
<source>stats.amountTotal</source>
<target>Umsatz total</target>
</trans-unit>
<!--
Dashboard
-->
<trans-unit id="stats.userTotal">
<source>stats.userTotal</source>
<target>Anzahl Benutzer</target>
</trans-unit>
<trans-unit id="stats.userActiveThisMoth">
<source>stats.userActiveThisMoth</source>
<target>Aktive Benutzer diesen Monat</target>
</trans-unit>
<trans-unit id="stats.userActiveEver">
<source>stats.userActiveEver</source>
<target>Aktive Benutzer jemals</target>
</trans-unit>
<trans-unit id="stats.activeRecordings">
<source>stats.activeRecordings</source>
<target>Momentan aktive Zeitmessungen</target>
</trans-unit>
<trans-unit id="stats.activitiesTotal">
<source>stats.activitiesTotal</source>
<target>Anzahl Aktivitäten</target>
</trans-unit>
<trans-unit id="stats.projectsTotal">
<source>stats.projectsTotal</source>
<target>Anzahl Projekte</target>
</trans-unit>
<trans-unit id="stats.customerTotal">
<source>stats.customerTotal</source>
<target>Anzahl Kunden</target>
</trans-unit>
<!--
Month names
-->
<trans-unit id="month.1">
<source>month.1</source>
<target>Januar</target>
</trans-unit>
<trans-unit id="month.2">
<source>month.2</source>
<target>Februar</target>
</trans-unit>
<trans-unit id="month.3">
<source>month.3</source>
<target>März</target>
</trans-unit>
<trans-unit id="month.4">
<source>month.4</source>
<target>April</target>
</trans-unit>
<trans-unit id="month.5">
<source>month.5</source>
<target>Mai</target>
</trans-unit>
<trans-unit id="month.6">
<source>month.6</source>
<target>Juni</target>
</trans-unit>
<trans-unit id="month.7">
<source>month.7</source>
<target>Juli</target>
</trans-unit>
<trans-unit id="month.8">
<source>month.8</source>
<target>August</target>
</trans-unit>
<trans-unit id="month.9">
<source>month.9</source>
<target>September</target>
</trans-unit>
<trans-unit id="month.10">
<source>month.10</source>
<target>Oktober</target>
</trans-unit>
<trans-unit id="month.11">
<source>month.11</source>
<target>November</target>
</trans-unit>
<trans-unit id="month.12">
<source>month.12</source>
<target>Dezember</target>
</trans-unit>
<!--
Navbar - recent entries and activities
-->
<trans-unit id="active.entries">
<source>active.entries</source>
<target>Sie haben %count% aktiven Eintrag|Sie haben %count% aktive Einträge</target>
</trans-unit>
<trans-unit id="timesheet.all">
<source>timesheet.all</source>
<target>Alle Einträge anzeigen</target>
</trans-unit>
<trans-unit id="recent.activities">
<source>recent.activities</source>
<target>Ihr %count% zuletzt bearbeitete Aktivität|Eine ihrer %count% letzten Aktivitäten neustarten</target>
</trans-unit>
<trans-unit id="recent.activities.format">
<source>recent.activities.format</source>
<target>%activity% in %project% für %customer%</target>
</trans-unit>
<trans-unit id="timesheet.start">
<source>timesheet.start</source>
<target>Neue Zeitmessung starten</target>
</trans-unit>
<!--
TOOLBARS
-->
<trans-unit id="label.pageSize">
<source>label.pageSize</source>
<target>Anzahl Einträge</target>
</trans-unit>
<trans-unit id="label.entryState">
<source>label.entryState</source>
<target>Zeiten</target>
</trans-unit>
<trans-unit id="entryState.all">
<source>entryState.all</source>
<target>Alle</target>
</trans-unit>
<trans-unit id="entryState.running">
<source>entryState.running</source>
<target>Laufende</target>
</trans-unit>
<trans-unit id="entryState.stopped">
<source>entryState.stopped</source>
<target>Beendete</target>
</trans-unit>
<trans-unit id="0">
<source>0</source>
<target>0</target>
</trans-unit>
<trans-unit id="10">
<source>10</source>
<target>10</target>
</trans-unit>
<trans-unit id="25">
<source>25</source>
<target>25</target>
</trans-unit>
<trans-unit id="50">
<source>50</source>
<target>50</target>
</trans-unit>
<trans-unit id="75">
<source>75</source>
<target>75</target>
</trans-unit>
<trans-unit id="100">
<source>100</source>
<target>100</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file date="2016-10-19T21:46:45Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<trans-unit id="previous">
<source>previous</source>
<target>Vorherige</target>
</trans-unit>
<trans-unit id="next">
<source>next</source>
<target>Nächste</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="de" datatype="plaintext" original="not.available">
<body>
<trans-unit id="This value is not a valid role.">
<source>This value is not a valid role.</source>
<target>Dieser Wert ist keine gültige Rolle.</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -1,100 +0,0 @@
{% extends 'AvanzuAdminThemeBundle:layout:default-layout.html.twig' %}
{% block avanzu_page_content %}
{{ include('default/_flash_messages.html.twig') }}
{% block main %}{% endblock %}
{% endblock %}
{% block avanzu_document_title %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %}
{% endblock %}
{% block avanzu_page_title %}
{% block page_title %}{% endblock %}
{% endblock %}
{% block avanzu_page_subtitle %}
{% block page_subtitle %}{% endblock %}
{% endblock %}
{% block avanzu_logo_path %}
{{ path('dashboard') }}
{% endblock %}
{% block avanzu_logo_mini %}
<b>K</b>TT
{% endblock %}
{% block avanzu_logo_lg %}
<b>Kimai</b> - Time Tracking
{% endblock %}
{% block avanzu_head %}
<link rel="stylesheet" href="{{ asset('css/kimai.css') }}">
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
{% endblock %}
{% block avanzu_footer %}
{% block footer %}
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> 2.0
</div>
<strong>Copyright &copy; {{ 'now'|date('Y') }} - <a href="http://www.kevinpapst.de">Kevin Papst</a></strong>.
{{ 'footer.license'|trans }}
</footer>
<!-- Page rendered on {{ 'now'|localizeddate('long', 'long', null, 'UTC') }} -->
{% endblock %}
{% endblock %}
{% block avanzu_navbar_messages %}
{% if app.user is not null and is_granted('IS_AUTHENTICATED_FULLY') %}
{{ render(controller('TimesheetBundle:Timesheet:activeEntries')) }}
{% endif %}
{% endblock %}
{% block avanzu_navbar_notifications %}
{% if app.user is not null and is_granted('IS_AUTHENTICATED_FULLY') %}
{{ render(controller('TimesheetBundle:Activity:recentActivities')) }}
{% endif %}
{#
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-globe"></i> <span class="caret"></span></a>
<ul class="dropdown-menu locales" role="menu">
{% for locale in locales() %}
<li {% if app.request.locale == locale.code %}class="active"{% endif %}><a href="{{ path(app.request.get('_route', 'homepage'), app.request.get('_route_params', [])|merge({ _locale: locale.code })) }}">{{ locale.name|capitalize }}</a></li>
{% endfor %}
</ul>
</li>
#}
{% endblock %}
{% block avanzu_navbar_toggle %}{{ parent() }}{% endblock %}
{% block avanzu_navbar_tasks %}{{ parent() }}{% endblock %}
{% block avanzu_navbar_user %}{{ parent() }}{% endblock %}
{% block avanzu_navbar_control_sidebar_toggle %}{{ parent() }}{% endblock %}
{% block avanzu_sidebar_user %}{# right now we simply deactivate that box #}{% endblock %}
{% block avanzu_sidebar_search %}{# right now we simply deactivate that box #}{% endblock %}
{% block avanzu_sidebar_nav %}{{ parent() }}{% endblock %}
{% block avanzu_breadcrumb %}{{ parent() }}{% endblock %}
{% block avanzu_control_sidebar %}{{ parent() }}{% endblock %}
{% block avanzu_javascripts %}
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="{{ asset('theme/bootstrap/js/bootstrap.min.js') }}"></script>
<script src="{{ asset('js/kimai.js') }}"></script>
<script src="{{ asset('js/Chart.min.js') }}"></script>
{% block javascript_imports %}{% endblock %}
{% endblock %}
{% block avanzu_javascripts_inline %}
<script type="text/javascript">
$(document).ready(function () {
$('.dropdown-toggle').dropdown();
$(document).kimai({imagePath: '{{ asset('images') }}', confirmDelete: '{{ 'confirm.delete'|trans }}'});
//$(document).kimai('pauseRecord', 'li.messages-menu ul.menu li');
});
</script>
{% endblock %}

View File

@@ -1,16 +0,0 @@
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ title }}</h3>
</div>
{{ form_start(form) }}
<div class="box-body">
{{ form_widget(form) }}
</div>
<div class="box-footer">
<input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
{% if back %}
<a href="{{ back }}" class="btn btn-warning">{{ 'action.back'|trans }}</a>
{% endif %}
</div>
{{ form_end(form) }}
</div>

View File

@@ -1,19 +0,0 @@
{#
Each field type is rendered by a template fragment, which is determined
by the name of your form type class (DateTimePickerType -> date_time_picker)
and the suffix "_widget". This can be controlled by overriding getBlockPrefix()
in DateTimePickerType.
See http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-a-template-for-the-field
#}
{% block date_time_picker_widget %}
{% spaceless %}
<div class="input-group date" data-toggle="datetimepicker">
{{ block('datetime_widget') }}
<span class="input-group-addon">
<span class="fa fa-calendar"></span>
</span>
</div>
{% endspaceless %}
{% endblock %}

View File

@@ -1,40 +0,0 @@
{% extends 'AvanzuAdminThemeBundle:layout:login-layout.html.twig' %}
{% block avanzu_login_title %}{{ 'browser.title'|trans }}{% endblock %}
{% block avanzu_logo_login %}<b>Kimai</b><br>TimeTracking{% endblock %}
{% block avanzu_login_box_msg %}
{{ 'security.title.login'|trans }}
{% if error|default(false) %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% endblock %}
{% block avanzu_login_form %}
<form action="{{ path('security_login') }}" method="post">
<div class="form-group has-feedback">
<input type="text" name="_username" class="form-control" placeholder="{{ 'security.label.username'|trans }}" value="{{ last_username }}">
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input name="_password" type="password" class="form-control" placeholder="{{ 'security.label.password'|trans }}">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="row">
<div class="col-xs-8">
{#
<div class="checkbox icheck">
<label>
<input type="checkbox"> {{ 'Remember Me'|trans({}, 'AvanzuAdminTheme') }}
</label>
</div>
#}
</div>
<div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">{{ 'security.action.sign_in'|trans }}</button>
</div>
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"/>
</form>
{% endblock %}
{% block avanzu_login_social_auth %}{% endblock %}
{% block avanzu_login_actions %}{% endblock %}

View File

@@ -1,13 +0,0 @@
<?php
use Doctrine\Common\Annotations\AnnotationRegistry;
use Composer\Autoload\ClassLoader;
/**
* @var ClassLoader $loader
*/
$loader = require __DIR__.'/../vendor/autoload.php';
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
return $loader;

View File

@@ -1,105 +0,0 @@
# This is the main configuration file of your application. It stores all the
# common options for every execution environment ('prod', 'dev', 'test').
# To avoid creating configuration files that are too long, we first import some
# files that define the values for important parts of the application,
# such as the security component and the dependency injection services
imports:
- { resource: parameters.yml }
- { resource: security.yml }
- { resource: services.yml }
# These are the configuration parameters that define the application's behavior
# and which are independent from the underlying technical infrastructure
# See http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
# This parameter defines the codes of the locales (languages) enabled in the application
app_locales: en|de
app.notifications.email_sender: "%mailer_from%"
# Basic configuration for the Symfony framework features
framework:
# Uncomment the 'ide' option to turn all of the file paths in an exception
# page into clickable links that open the given file using your favorite IDE.
# Supported values are 'textmate', 'macvim', 'emacs' and 'sublime' shortcuts
# and any custom configuration string, such as: "phpstorm://open?file=%%f&line=%%l"
# See http://symfony.com/doc/current/reference/configuration/framework.html#ide
#ide: sublime
# When using the HTTP Cache, ESI allows to render page fragments separately
# and with different cache configurations for each fragment
# http://symfony.com/doc/current/book/http_cache.html#edge-side-includes
esi: { enabled: true }
translator: { fallback: "%locale%" }
secret: "%secret%"
router:
resource: "%kernel.root_dir%/config/routing.yml"
strict_requirements: ~
form: ~
csrf_protection: ~
validation: { enable_annotations: true }
templating:
engines: ['twig']
default_locale: "%locale%"
trusted_hosts: ~
session:
handler_id: session.handler.native_file
save_path: "%kernel.root_dir%/../var/sessions/%kernel.environment%"
fragments: ~
http_method_override: true
assets: ~
# Twig Configuration (used for rendering application templates)
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"
# form_themes:
# - "bootstrap_3_layout.html.twig"
# - "form/fields.html.twig"
globals:
kimai_context:
date_1: "d.m.Y" # used for display in timesheets
box_color: "green" # a color for ???
active_warning: 3 # display a warning color if the user has at least X active recordings
# Assetic Configuration (used for managing web assets: CSS, JavaScript, Sass, etc.)
#assetic:
# debug: "%kernel.debug%"
# use_controller: false
# bundles: [ ]
# filters:
# cssrewrite: ~
# jsqueeze: ~
# scssphp:
# # the formatter must be the FQCN (don't use the 'compressed' value)
# formatter: "Leafo\\ScssPhp\\Formatter\\Compressed"
# Doctrine Configuration (used to access databases and manipulate their information)
doctrine:
dbal:
url: "%database_url%"
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
# Swiftmailer Configuration (used to send emails)
#swiftmailer:
# transport: "%mailer_transport%"
# host: "%mailer_host%"
# username: "%mailer_user%"
# password: "%mailer_password%"
# spool: { type: memory }
avanzu_admin_theme:
use_twig: true
use_assetic: true
bower_bin: "/usr/local/bin/bower"
options:
default_avatar: avatars/default.png
skin: skin-green-light
fixed_layout: false
boxed_layout: false
collapsed_sidebar: true
mini_sidebar: true
control_sidebar: false

View File

@@ -1,47 +0,0 @@
imports:
- { resource: config.yml }
- { resource: services_dev.yml }
framework:
router:
resource: "%kernel.root_dir%/config/routing_dev.yml"
strict_requirements: true
profiler: { only_exceptions: false }
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
console:
type: console
bubble: false
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
#assetic:
# use_controller: true
#swiftmailer:
# delivery_address: me@example.com
services:
twig.text_extension:
class: Twig_Extensions_Extension_Text
tags:
- name: twig.extension
web_profiler:
toolbar: '%kernel.debug%'
intercept_redirects: false
# See routing_dev.yml
#avanzu_admin_theme:
# enable_demo: false

View File

@@ -1,25 +0,0 @@
imports:
- { resource: config.yml }
#framework:
# cache:
# system: cache.adapter.apcu
#doctrine:
# orm:
# metadata_cache_driver: apc
# result_cache_driver: apc
# query_cache_driver: apc
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
console:
type: console

View File

@@ -1,31 +0,0 @@
imports:
- { resource: config_dev.yml }
framework:
test: ~
session:
storage_id: session.storage.mock_file
profiler:
collect: false
web_profiler:
toolbar: false
intercept_redirects: false
swiftmailer:
disable_delivery: true
# It's recommended to use a separate database for tests. This allows to have a
# fixed and known set of data fixtures, it simplifies the code of tests and it
# makes them more robust.
# In this case we just need to define a different path for the application database.
doctrine:
dbal:
database_url: 'sqlite:///%kernel.root_dir%/data/timesheet_test.sqlite'
# this configuration simplifies testing URLs protected by the security mechanism
# See http://symfony.com/doc/current/cookbook/testing/http_authentication.html
security:
firewalls:
secured_area:
http_basic: ~

View File

@@ -1,86 +0,0 @@
doctrine:
orm:
dql:
datetime_functions:
convert_tz: DoctrineExtensions\Query\Mysql\ConvertTz
date: DoctrineExtensions\Query\Mysql\Date
date_format: DoctrineExtensions\Query\Mysql\DateFormat
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
datesub: DoctrineExtensions\Query\Mysql\DateSub
datediff: DoctrineExtensions\Query\Mysql\DateDiff
day: DoctrineExtensions\Query\Mysql\Day
dayname: DoctrineExtensions\Query\Mysql\DayName
dayofweek: DoctrineExtensions\Query\Mysql\DayOfWeek
dayofyear: DoctrineExtensions\Query\Mysql\DayOfYear
div: DoctrineExtensions\Query\Mysql\Div
from_unixtime: DoctrineExtensions\Query\Mysql\FromUnixtime
last_day: DoctrineExtensions\Query\Mysql\LastDay
minute: DoctrineExtensions\Query\Mysql\Minute
now: DoctrineExtensions\Query\Mysql\Now
month: DoctrineExtensions\Query\Mysql\Month
monthname: DoctrineExtensions\Query\Mysql\MonthName
second: DoctrineExtensions\Query\Mysql\Second
strtodate: DoctrineExtensions\Query\Mysql\StrToDate
time: DoctrineExtensions\Query\Mysql\Time
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
timestampadd: DoctrineExtensions\Query\Mysql\TimestampAdd
timestampdiff: DoctrineExtensions\Query\Mysql\TimestampDiff
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
week: DoctrineExtensions\Query\Mysql\Week
weekday: DoctrineExtensions\Query\Mysql\WeekDay
year: DoctrineExtensions\Query\Mysql\Year
yearweek: DoctrineExtensions\Query\Mysql\YearWeek
unix_timestamp: DoctrineExtensions\Query\Mysql\UnixTimestamp
numeric_functions:
acos: DoctrineExtensions\Query\Mysql\Acos
asin: DoctrineExtensions\Query\Mysql\Asin
atan2: DoctrineExtensions\Query\Mysql\Atan2
atan: DoctrineExtensions\Query\Mysql\Atan
bit_count: DoctrineExtensions\Query\Mysql\BitCount
bit_xor: DoctrineExtensions\Query\Mysql\BitXor
ceil: DoctrineExtensions\Query\Mysql\Ceil
cos: DoctrineExtensions\Query\Mysql\Cos
cot: DoctrineExtensions\Query\Mysql\Cot
floor: DoctrineExtensions\Query\Mysql\Floor
hour: DoctrineExtensions\Query\Mysql\Hour
pi: DoctrineExtensions\Query\Mysql\Pi
power: DoctrineExtensions\Query\Mysql\Power
quarter: DoctrineExtensions\Query\Mysql\Quarter
rand: DoctrineExtensions\Query\Mysql\Rand
round: DoctrineExtensions\Query\Mysql\Round
stddev: DoctrineExtensions\Query\Mysql\StdDev
sin: DoctrineExtensions\Query\Mysql\Sin
std: DoctrineExtensions\Query\Mysql\Std
tan: DoctrineExtensions\Query\Mysql\Tan
string_functions:
ascii: DoctrineExtensions\Query\Mysql\Ascii
binary: DoctrineExtensions\Query\Mysql\Binary
char_length: DoctrineExtensions\Query\Mysql\CharLength
concat_ws: DoctrineExtensions\Query\Mysql\ConcatWs
countif: DoctrineExtensions\Query\Mysql\CountIf
crc32: DoctrineExtensions\Query\Mysql\Crc32
degrees: DoctrineExtensions\Query\Mysql\Degrees
field: DoctrineExtensions\Query\Mysql\Field
find_in_set: DoctrineExtensions\Query\Mysql\FindInSet
greatest: DoctrineExtensions\Query\Mysql\Greatest
group_concat: DoctrineExtensions\Query\Mysql\GroupConcat
ifelse: DoctrineExtensions\Query\Mysql\IfElse
ifnull: DoctrineExtensions\Query\Mysql\IfNull
least: DoctrineExtensions\Query\Mysql\Least
lpad: DoctrineExtensions\Query\Mysql\Lpad
match_against: DoctrineExtensions\Query\Mysql\MatchAgainst
md5: DoctrineExtensions\Query\Mysql\Md5
nullif: DoctrineExtensions\Query\Mysql\NullIf
radians: DoctrineExtensions\Query\Mysql\Radians
regexp: DoctrineExtensions\Query\Mysql\Regexp
replace: DoctrineExtensions\Query\Mysql\Replace
rpad: DoctrineExtensions\Query\Mysql\Rpad
sha1: DoctrineExtensions\Query\Mysql\Sha1
sha2: DoctrineExtensions\Query\Mysql\Sha2
soundex: DoctrineExtensions\Query\Mysql\Soundex
substring_index: DoctrineExtensions\Query\Mysql\SubstringIndex
uuid_short: DoctrineExtensions\Query\Mysql\UuidShort
hex: DoctrineExtensions\Query\Mysql\Hex
unhex: DoctrineExtensions\Query\Mysql\Unhex

View File

@@ -1,37 +0,0 @@
# This file defines the canonical configuration parameters of the application.
# Symfony uses this file as a template to generate the real app/config/parameters.yml used by the application.
# See http://symfony.com/doc/current/best_practices/configuration.html#canonical-parameters
parameters:
# used to load additional doctrine functions (possible values: mysql, sqlite)
database_engine: sqlite
# Define the database connection string
database_url: 'sqlite:///%kernel.root_dir%/data/timesheet.sqlite'
# database_url: 'mysql://root:pass@127.0.0.1:3306/timesheet'
# You can prefix all your tables to pevent collision with other software
database_prefix: kimai2_
# You can create the database and load the sample data from the command line:
#
# php bin/console doctrine:database:create
# php bin/console doctrine:schema:create
# php bin/console doctrine:fixtures:load
# If you don't use a real mail server, you can send emails via your Gmail account.
# see http://symfony.com/doc/current/cookbook/email/gmail.html
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: ~
mailer_password: ~
mailer_from: anonymous@example.com
# The code of the default language used by the application ('en' = English, 'de' = German)
locale: de
# The 'secret' value is a random string of characters, numbers and symbols
# used internally by Symfony in several places (CSRF tokens, URI signing,
# 'Remember Me' functionality, etc.)
# see: http://symfony.com/doc/current/reference/configuration/framework.html#secret
secret: 'please_change_this_secret_to_something_unique'

View File

@@ -1,39 +0,0 @@
# These first lines load the all routes defined as @Route() annotations in any
# controller defined inside the src/AppBundle/Controller/ directory. Controllers
# are loaded recursively, so you can separate them into subdirectories.
# If you don't like to add annotations in your applications, you can also define
# the routes in YAML, XML or PHP files.
# See http://symfony.com/doc/current/book/routing.html
app:
resource: '@AppBundle/Controller/'
type: annotation
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
timesheet:
resource: '@TimesheetBundle/Controller/'
type: annotation
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
# These lines define a route using YAML configuration. The controller used by
# the route (FrameworkBundle:Template:template) is a convenient shortcut when
# the template can be rendered without executing any logic in your own controller.
# See http://symfony.com/doc/current/cookbook/templating/render_without_controller.html
homepage:
path: /{_locale}
defaults:
_controller: FrameworkBundle:Redirect:redirect
route: timesheet
permanent: true
avanzu_admin_profile:
path: /{_locale}/profile/{username}
options:
avanzu_admin_route: profile

View File

@@ -1,35 +0,0 @@
# this imports the routes used to display the web debug toolbar at the bottom of each page
_wdt:
resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
prefix: /_wdt
# this imports the routes needed to display the Symfony Profiler information
_profiler:
resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
prefix: /_profiler
# this imports the route used to test error pages. Just browse the following URL:
# /{_locale}/_error/{status_code}.{format}
# (e.g. /en/_error/404, /en/_error/403.json, /fr/_error/500.xml)
# See http://symfony.com/doc/current/cookbook/controller/error_pages.html#testing-error-pages-during-development
_errors:
resource: "@TwigBundle/Resources/config/routing/errors.xml"
prefix: /{_locale}/_error
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'
# this loads the main routing file, which usually defines the routes available
# in any environment (production, development, etc.)
_main:
resource: routing.yml
# ========================================================================
# Demo routes, only work with "avanzu_admin_theme/enable_demo: true"
# ========================================================================
#avanzu_admin:
# prefix: /admin
# resource: "@AvanzuAdminThemeBundle/Resources/config/routes.yml"

View File

@@ -1,177 +0,0 @@
services:
# ================================================================================
# TWIG
# ================================================================================
markdown:
class: AppBundle\Utils\Markdown
app.twig.app_extension:
public: false
class: AppBundle\Twig\Extensions
arguments: ['@markdown', '%app_locales%']
tags:
- { name: twig.extension }
# twig function: template_from_string()
app.twig.loader_extension:
class: Twig_Extension_StringLoader
tags:
- { name: 'twig.extension' }
app.twig.intl_extension:
public: false
class: Twig_Extensions_Extension_Intl
tags:
- { name: twig.extension }
# ================================================================================
# SECURITY
# ================================================================================
# security voter to check user-profile access
app.voter.user:
class: AppBundle\Voter\UserVoter
arguments: ["@security.access.decision_manager"]
tags:
- { name: security.voter }
# security voter to check customer access
timesheet.voter.customer:
class: TimesheetBundle\Voter\CustomerVoter
arguments: ["@security.access.decision_manager"]
tags:
- { name: security.voter }
# security voter to check project access
timesheet.voter.project:
class: TimesheetBundle\Voter\ProjectVoter
arguments: ["@security.access.decision_manager"]
tags:
- { name: security.voter }
# security voter to check activity access
timesheet.voter.activity:
class: TimesheetBundle\Voter\ActivityVoter
arguments: ["@security.access.decision_manager"]
tags:
- { name: security.voter }
# security voter to check activity access
timesheet.voter.timesheet:
class: TimesheetBundle\Voter\TimesheetVoter
arguments: ["@security.access.decision_manager"]
tags:
- { name: security.voter }
# ================================================================================
# FORMS
# ================================================================================
# form to edit user roles
app.admin.user_role:
class: AppBundle\Form\Type\UserRoleType
arguments: ["%security.role_hierarchy.roles%"]
tags:
- { name: form.type }
# event-listener to populate the navigation
app.menu_builder:
class: AppBundle\EventListener\MenuBuilder
arguments: ["@event_dispatcher", "@security.authorization_checker"]
tags:
- { name: kernel.event_listener, event: theme.sidebar_setup_menu, method: onSetupNavbar }
# ================================================================================
# DATABASE
# ================================================================================
# service that prefixes every database table
app.tableprefix_subscriber:
class: AppBundle\Doctrine\TablePrefixSubscriber
arguments: ["%database_prefix%"]
tags:
- { name: doctrine.event_subscriber }
app.database_listener.timesheet:
class: TimesheetBundle\EventListener\TimesheetListener
tags:
- { name: doctrine.event_listener, event: prePersist, lazy: true }
- { name: doctrine.event_listener, event: preUpdate, lazy: true }
# Uncomment the following lines to define a service for the Post Doctrine repository.
# It's not mandatory to create these services, but if you use repositories a lot,
# these services simplify your code:
#
# app.post_repository:
# class: Doctrine\ORM\EntityRepository
# factory: ['@doctrine.orm.entity_manager', getRepository]
# arguments: [AppBundle\Entity\User]
#
# // traditional code inside a controller
# $entityManager = $this->getDoctrine()->getManager();
# $posts = $entityManager->getRepository('AppBundle:User')->findAll();
#
# // same code using repository services
# $posts = $this->get('app.user_repository')->findAll();
# ================================================================================
# THEME
# ================================================================================
avanzu_admin_theme.navbar_user_listener:
class: AppBundle\EventListener\NavbarShowUserListener
arguments: ["@security.token_storage"]
tags:
- { name: kernel.event_listener, event: theme.navbar_user, method: onShowUser }
- { name: kernel.event_listener, event: theme.sidebar_user, method: onShowUser }
# avanzu_admin_theme.navbar_task_listener:
# class: "%avanzu_admin_theme.navbar_task_listener.class%"
# tags:
# - { name: kernel.event_listener, event: theme.tasks, method: onListTasks }
#
# avanzu_admin_theme.navbar_notify_listener:
# class: "%avanzu_admin_theme.navbar_notify_listener.class%"
# tags:
# - { name: kernel.event_listener, event: theme.notifications, method: onListNotifications }
#
# avanzu_admin_theme.navbar_msg_listener:
# class: "%avanzu_admin_theme.navbar_msg_listener.class%"
# tags:
# - { name: kernel.event_listener, event: theme.messages, method: onListMessages }
#
# avanzu_admin_theme.setup_menu_listener:
# class: "%avanzu_admin_theme.setup_menu_listener.class%"
# tags:
# - { name: kernel.event_listener, event: theme.sidebar_setup_menu, method: onSetupMenu }
# - { name: kernel.event_listener, event: theme.breadcrumb, method: onSetupMenu }
# ================================================================================
# APPLICATION CORE
# ================================================================================
# a route listener, that injects the locale through a URL directory
app.redirect_to_preferred_locale_listener:
class: AppBundle\EventListener\RedirectToPreferredLocaleListener
arguments: ['@router', '%app_locales%', '%locale%']
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
# additional menu entries for the timesheet bundle
timesheet.configure_menu_listener:
class: TimesheetBundle\EventListener\Menu
tags:
- { name: kernel.event_listener, event: app.main_menu_configure, method: onMainMenuConfigure }
- { name: kernel.event_listener, event: app.admin_menu_configure, method: onAdminMenuConfigure }
# ================================================================================
# CONSOLE COMMANDS
# ================================================================================
app.command.create_user:
class: AppBundle\Command\CreateUserCommand
arguments: ["@security.password_encoder", "@doctrine", "@validator"]
tags:
- { name: console.command, command: kimai:create-user }

View File

@@ -1,32 +0,0 @@
imports:
- { resource: services.yml }
services:
# ================================================================================
# CONSOLE COMMANDS
# ================================================================================
app.command.run_phpcs:
class: AppBundle\Command\RunCodeSnifferCommand
arguments: ["%kernel.root_dir%"]
tags:
- { name: console.command, command: kimai:dev:phpcs }
app.command.run_unit_tests:
class: AppBundle\Command\RunUnitTestsCommand
arguments: ["%kernel.root_dir%"]
tags:
- { name: console.command, command: kimai:dev:test-unit }
app.command.run_integration_tests:
class: AppBundle\Command\RunIntegrationTestsCommand
arguments: ["%kernel.root_dir%"]
tags:
- { name: console.command, command: kimai:dev:test-integration }
app.command.dev_reset:
class: AppBundle\Command\DevResetCommand
arguments: ["%kernel.root_dir%"]
tags:
- { name: console.command, command: kimai:dev:reset }

View File

@@ -1,50 +0,0 @@
doctrine:
orm:
dql:
datetime_functions:
date: DoctrineExtensions\Query\Sqlite\Date
date_format: DoctrineExtensions\Query\Sqlite\DateFormat
#dateadd: DoctrineExtensions\Query\Sqlite\DateAdd
#datediff: DoctrineExtensions\Query\Sqlite\DateDiff
day: DoctrineExtensions\Query\Sqlite\Day
dayname: DoctrineExtensions\Query\Sqlite\DayName
minute: DoctrineExtensions\Query\Sqlite\Minute
#month: DoctrineExtensions\Query\Sqlite\Month
#monthname: DoctrineExtensions\Query\Sqlite\MonthName
second: DoctrineExtensions\Query\Sqlite\Second
month: DoctrineExtensions\Query\Sqlite\Month
strftime: DoctrineExtensions\Query\Sqlite\StrfTime
#strtodate: DoctrineExtensions\Query\Sqlite\StrToDate
#time: DoctrineExtensions\Query\Sqlite\Time
#timestampadd: DoctrineExtensions\Query\Sqlite\TimestampAdd
#timestampdiff: DoctrineExtensions\Query\Sqlite\TimestampDiff
week: DoctrineExtensions\Query\Sqlite\Week
weekday: DoctrineExtensions\Query\Sqlite\WeekDay
year: DoctrineExtensions\Query\Sqlite\Year
string_functions:
# binary: DoctrineExtensions\Query\Sqlite\Binary
# char_length: DoctrineExtensions\Query\Sqlite\CharLength
concat_ws: DoctrineExtensions\Query\Sqlite\ConcatWs
# countif: DoctrineExtensions\Query\Sqlite\CountIf
# crc32: DoctrineExtensions\Query\Sqlite\Crc32
# degrees: DoctrineExtensions\Query\Sqlite\Degrees
# field: DoctrineExtensions\Query\Sqlite\Field
# find_in_set: DoctrineExtensions\Query\Sqlite\FindInSet
# group_concat: DoctrineExtensions\Query\Sqlite\GroupConcat
# ifelse: DoctrineExtensions\Query\Sqlite\IfElse
ifnull: DoctrineExtensions\Query\Sqlite\IfNull
# match_against: DoctrineExtensions\Query\Sqlite\MatchAgainst
# md5: DoctrineExtensions\Query\Sqlite\Md5
# nullif: DoctrineExtensions\Query\Sqlite\NullIf
# radians: DoctrineExtensions\Query\Sqlite\Radians
# regexp: DoctrineExtensions\Query\Sqlite\Regexp
replace: DoctrineExtensions\Query\Sqlite\Replace
# sha1: DoctrineExtensions\Query\Sqlite\Sha1
# sha2: DoctrineExtensions\Query\Sqlite\Sha2
# soundex: DoctrineExtensions\Query\Sqlite\Soundex
# uuid_short: DoctrineExtensions\Query\Sqlite\UuidShort
numeric_functions:
round: DoctrineExtensions\Query\Sqlite\Round

View File

@@ -1,3 +1,42 @@
/*
* 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-sass/assets/stylesheets/bootstrap/variables";
.error-page {
margin-bottom: 50px;
}
/* ================================ CONTENT ================================ */
.content {
padding: 15px 0;
}
.content-header {
h1 {
small {
display: none;
}
}
}
@media (min-width: $screen-sm-min) {
.content-header {
h1 {
small {
display: inline-block;
}
}
}
.content {
padding: 15px;
}
}
/* ================================ NAVBAR ================================ */
.navbar-nav>li>a.ddt-large {
@@ -5,9 +44,8 @@
padding-bottom: 9px;
}
li.messages-menu ul.menu li:hover .pull-left i {
li.messages-menu ul.menu li .pull-left i {
color: #dd4b39;
}
.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p {
@@ -15,6 +53,10 @@ li.messages-menu ul.menu li:hover .pull-left i {
text-overflow: ellipsis;
}
.navbar-nav .start_record {
text-align: center;
}
/*
.ticktac:hover i.running{
color: #4ff131;
@@ -39,27 +81,27 @@ li.open .ticktac i.running{
/* ================================ TOOLBAR ================================ */
.data_table .box-header>.box-tools {
top: 3px;
/* Page based action buttons in the upper right corner of the content area */
.content-header > .breadcrumb {
position: absolute;
float: right;
background: transparent;
}
.box-header .box-title.toolbar form {
font-size: 13px;
/* Right sidebar with additional tabs for personal settings and "About Kimai" section */
.control-sidebar {
select {
color: #000;
}
div.image {
img.img-circle {
max-width: 34px;
}
}
}
.toolbar form input,
.toolbar form select {
display: inline-block;
width: inherit;
/* The filter form available on most pages above the datatable */
.toolbar form {
font-size: $font-size-base;
}
.toolbar form .form-group {
display: inline;
}
.box-header .tools-left {
margin-right: 10px;
}
/* ================================ SIDEBAR ================================ */
/* Used for the Sidebar UserPanel (which is deactivated right now) */
@@ -74,16 +116,51 @@ footer.main-footer {
font-size: 80%;
}
/* ================================ LOGIN-PAGE ================================ */
.login-page form label {
padding-left: 5px;
}
/* ================================ PRINT ================================ */
@media print{
.sf-toolbar, .control-sidebar {display: none !important;}
}
/* ================================ INVOICES ================================ */
.invoice {
margin: 0;
}
@media (min-width: $screen-sm-min) {
.invoice {
margin: 10px 25px;
}
}
.page-header-small{
font-size: 14px;
}
div.invoice-address {
margin-top: 30px;
margin-bottom: 30px;
}
table.invoice-records {}
table.invoice-meta th {
padding-right: 40px;
}
table.invoice-sum th {
width: 70%;
}
table.invoice-sum th, table.invoice-sum td {
text-align: right;
}
/* ================================ DATA-TABLES ================================ */
/*
TODO "display:hidden" regel für dataTable - spalten - mobile ansicht
TODO "display:hidden" regel für dataTable - header icon - mobile ansicht
*/
/*
dataTables.bootstrap.css
*/
@@ -131,7 +208,6 @@ div.dataTables_paginate ul.pagination {
}
@media screen and (max-width: 767px) {
div.dataTables_wrapper > div.row > div,
div.dataTables_length,
div.dataTables_filter,
div.dataTables_info,
@@ -144,7 +220,6 @@ div.dataTables_paginate ul.pagination {
}
}
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
@@ -152,7 +227,6 @@ table.dataTable th {
box-sizing: content-box;
}
table.dataTable {
clear: both;
/*margin-top: 6px !important;
@@ -281,9 +355,6 @@ div.dataTables_scrollHead table.table-bordered {
border-bottom-width: 0;
}
/*
* TableTools styles
*/

8
assets/css/vendor.scss Normal file
View File

@@ -0,0 +1,8 @@
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
$fa-font-path: "~font-awesome/fonts";
@import '~bootstrap-sass/assets/stylesheets/bootstrap';
@import '~font-awesome/scss/font-awesome';
@import '~daterangepicker/daterangepicker.css';
@import '~bootstrap-select/dist/css/bootstrap-select.min.css';

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

36
assets/js/app.js Normal file
View File

@@ -0,0 +1,36 @@
// ------ jquery and bootstrap basics ------
// create global $ and jQuery variables
const $ = require('jquery');
global.$ = global.jQuery = $;
require('jquery-ui');
require('bootstrap-sass');
require('jquery-slimscroll');
require('bootstrap-select');
const Moment = require('moment');
global.moment = Moment;
require('daterangepicker');
// ------ for charts ------
const Chart = require('../../vendor/almasaeed2010/adminlte/plugins/chartjs/Chart.min.js');
global.Chart = Chart;
// ------ AdminLTE framework ------
require('../css/vendor.scss');
require('../../vendor/almasaeed2010/adminlte/dist/css/AdminLTE.min.css');
require('../../vendor/almasaeed2010/adminlte/dist/css/skins/_all-skins.css');
require('../css/kimai.scss');
global.$.AdminLTE = {};
global.$.AdminLTE.options = {};
require('../../vendor/almasaeed2010/adminlte/dist/js/app.js');
// ------ Kimai itself ------
require('./kimai.js');
require('./toolbar.js');
require('../images/default_avatar.png');
// ------ icheck for enhanced radio buttins and checkboxes ------
require('icheck');
require('icheck/skins/square/blue.css');

110
assets/js/kimai.js Normal file
View File

@@ -0,0 +1,110 @@
/*
* 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.
*/
if (typeof jQuery === 'undefined') {
throw new Error('Kimai requires jQuery');
}
/* kimai
*
* @type Object
* @description $.kimai is the main object for the template's app.
* It's used for implementing functions and options related
* to the template. Keeping everything wrapped in an object
* prevents conflict with other plugins and is a better
* way to organize our code.
*/
$.kimai = {};
$(function() {
"use strict";
$.kimai = {
init: function(options) {
if (typeof options !== 'undefined') {
$.kimai.settings = $.extend({}, $.kimai.defaults, options);
}
// ask before a delete call is executed
$('a.btn-trash').click(function (event) {
return confirm($.kimai.settings['confirmDelete']);
});
// activate the dropdown functionality
$('.dropdown-toggle').dropdown();
// auto hide success message after x seconds, as they are just meant as quick feedback and
// not as a permanent source of information
if ($.kimai.settings['alertSuccessAutoHide'] > 0) {
setTimeout(
function() {
$('div.alert-success').alert('close');
},
$.kimai.settings['alertSuccessAutoHide']
);
}
$('input[data-datepicker="on"]').daterangepicker({
singleDatePicker: true,
showDropdowns: true,
locale: {
format: "YYYY-MM-DD",
firstDay: 1
}
});
$('input[data-datetimepicker="on"]').daterangepicker({
singleDatePicker: true,
timePicker: true,
timePicker24Hour: true,
showDropdowns: true,
autoUpdateInput: false,
locale: {
cancelLabel: 'Clear',
format: "YYYY-MM-DD HH:mm",
firstDay: 1
}
});
$('input[data-datetimepicker="on"]').on('apply.daterangepicker', function(ev, picker) {
$(this).val(picker.startDate.format('YYYY-MM-DD HH:mm'));
});
/*
$('input').iCheck({
checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue',
increaseArea: '20%' // optional
});
*/
// $.AdminLTE.pushMenu.expandOnHover();
},
pauseRecord: function(selector) {
$(selector + ' .pull-left i').hover(function () {
var link = $(this).parents('a');
link.attr('href', link.attr('href').replace('/stop', '/pause'));
$(this).removeClass('fa-stop-circle').addClass('fa-pause-circle').addClass('text-orange');
},function () {
var link = $(this).parents('a');
link.attr('href', link.attr('href').replace('/pause', '/stop'));
$(this).removeClass('fa-pause-circle').removeClass('text-orange').addClass('fa-stop-circle');
});
}
};
// default values
$.kimai.defaults = {
baseUrl: '/',
imagePath: '/images',
confirmDelete: 'Really delete?',
alertSuccessAutoHide: 5000
};
// once initialized, here are all values
$.kimai.settings = {};
});

View File

@@ -1,5 +1,18 @@
/*
* 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.
*/
$(document).ready(function () {
//$('.navbar-form select').selectpicker({});
// DateRange - TODO improve me, so users can type without reloading in between
$('.toolbar form input').change(function (event) {
$('.toolbar form').submit();
});
$('.toolbar form select').change(function (event) {
switch (event.target.id) {
case 'customer':

View File

@@ -1,29 +1,39 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Debug\Debug;
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
//umask(0000);
use Symfony\Component\Dotenv\Dotenv;
set_time_limit(0);
/**
* @var Composer\Autoload\ClassLoader $loader
*/
$loader = require __DIR__.'/../app/autoload.php';
require __DIR__.'/../vendor/autoload.php';
$input = new ArgvInput();
$env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev');
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod';
if ($debug) {
Debug::enable();
if (!class_exists(Application::class)) {
throw new \RuntimeException('You need to add "symfony/framework-bundle" as a Composer dependency.');
}
$kernel = new AppKernel($env, $debug);
if (!isset($_SERVER['APP_ENV'])) {
if (!class_exists(Dotenv::class)) {
throw new \RuntimeException('APP_ENV environment variable is not defined. You need to define environment variables for configuration or add "symfony/dotenv" as a Composer dependency to load variables from a .env file.');
}
(new Dotenv())->load(__DIR__.'/../.env');
}
$input = new ArgvInput();
$env = $input->getParameterOption(['--env', '-e'], $_SERVER['APP_ENV'] ?? 'dev');
$debug = ($_SERVER['APP_DEBUG'] ?? ('prod' !== $env)) && !$input->hasParameterOption(['--no-debug', '']);
if ($debug) {
umask(0000);
if (class_exists(Debug::class)) {
Debug::enable();
}
}
$kernel = new Kernel($env, $debug);
$application = new Application($kernel);
$application->run($input);

View File

@@ -1,146 +0,0 @@
#!/usr/bin/env php
<?php
require_once dirname(__FILE__).'/../var/SymfonyRequirements.php';
$lineSize = 70;
$symfonyRequirements = new SymfonyRequirements();
$iniPath = $symfonyRequirements->getPhpIniConfigPath();
echo_title('Symfony Requirements Checker');
echo '> PHP is using the following php.ini file:'.PHP_EOL;
if ($iniPath) {
echo_style('green', ' '.$iniPath);
} else {
echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!');
}
echo PHP_EOL.PHP_EOL;
echo '> Checking Symfony requirements:'.PHP_EOL.' ';
$messages = array();
foreach ($symfonyRequirements->getRequirements() as $req) {
if ($helpText = get_error_message($req, $lineSize)) {
echo_style('red', 'E');
$messages['error'][] = $helpText;
} else {
echo_style('green', '.');
}
}
$checkPassed = empty($messages['error']);
foreach ($symfonyRequirements->getRecommendations() as $req) {
if ($helpText = get_error_message($req, $lineSize)) {
echo_style('yellow', 'W');
$messages['warning'][] = $helpText;
} else {
echo_style('green', '.');
}
}
if ($checkPassed) {
echo_block('success', 'OK', 'Your system is ready to run Symfony projects');
} else {
echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects');
echo_title('Fix the following mandatory requirements', 'red');
foreach ($messages['error'] as $helpText) {
echo ' * '.$helpText.PHP_EOL;
}
}
if (!empty($messages['warning'])) {
echo_title('Optional recommendations to improve your setup', 'yellow');
foreach ($messages['warning'] as $helpText) {
echo ' * '.$helpText.PHP_EOL;
}
}
echo PHP_EOL;
echo_style('title', 'Note');
echo ' The command console could use a different php.ini file'.PHP_EOL;
echo_style('title', '~~~~');
echo ' than the one used with your web server. To be on the'.PHP_EOL;
echo ' safe side, please check the requirements from your web'.PHP_EOL;
echo ' server using the ';
echo_style('yellow', 'web/config.php');
echo ' script.'.PHP_EOL;
echo PHP_EOL;
exit($checkPassed ? 0 : 1);
function get_error_message(Requirement $requirement, $lineSize)
{
if ($requirement->isFulfilled()) {
return;
}
$errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL;
$errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL;
return $errorMessage;
}
function echo_title($title, $style = null)
{
$style = $style ?: 'title';
echo PHP_EOL;
echo_style($style, $title.PHP_EOL);
echo_style($style, str_repeat('~', strlen($title)).PHP_EOL);
echo PHP_EOL;
}
function echo_style($style, $message)
{
// ANSI color codes
$styles = array(
'reset' => "\033[0m",
'red' => "\033[31m",
'green' => "\033[32m",
'yellow' => "\033[33m",
'error' => "\033[37;41m",
'success' => "\033[37;42m",
'title' => "\033[34m",
);
$supports = has_color_support();
echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : '');
}
function echo_block($style, $title, $message)
{
$message = ' '.trim($message).' ';
$width = strlen($message);
echo PHP_EOL.PHP_EOL;
echo_style($style, str_repeat(' ', $width));
echo PHP_EOL;
echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT));
echo PHP_EOL;
echo_style($style, $message);
echo PHP_EOL;
echo_style($style, str_repeat(' ', $width));
echo PHP_EOL;
}
function has_color_support()
{
static $support;
if (null === $support) {
if (DIRECTORY_SEPARATOR == '\\') {
$support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
} else {
$support = function_exists('posix_isatty') && @posix_isatty(STDOUT);
}
}
return $support;
}

View File

@@ -1,81 +1,98 @@
{
"name": "keleo/kimai",
"name": "kimai/kimai",
"license": "MIT",
"type": "project",
"description": "Kimai Time Tracking reloaded",
"autoload": {
"psr-4": {
"": "src/",
"KimaiTest\\": "tests/"
},
"classmap": [
"app/AppKernel.php",
"app/AppCache.php"
]
},
"require": {
"php": ">=7.0.8",
"php": "^7.1.3",
"ext-pdo_sqlite": "*",
"doctrine/doctrine-bundle": "^1.6",
"doctrine/doctrine-fixtures-bundle": "^2.2",
"doctrine/orm": "^2.5",
"erusev/parsedown": "^1.5",
"ezyang/htmlpurifier": "^4.7",
"incenteev/composer-parameter-handler": "^2.0",
"leafo/scssphp": "^0.5",
"patchwork/jsqueeze": "^2.0",
"sensio/distribution-bundle": "^5.0",
"sensio/framework-extra-bundle": "^3.0",
"symfony/assetic-bundle": "^2.8",
"symfony/monolog-bundle": "^3.1",
"symfony/swiftmailer-bundle": "^2.3",
"symfony/symfony": "~3.4",
"twig/extensions": "^1.3",
"white-october/pagerfanta-bundle": "^1.0",
"avanzu/admin-theme-bundle": "dev-kevinpapst",
"beberlei/DoctrineExtensions": "^1.0",
"symfony/web-server-bundle": "3.4",
"avanzu/admin-theme-bundle": "dev-master"
"erusev/parsedown": "^1.6",
"ocramius/proxy-manager": "2.1.1",
"sensio/framework-extra-bundle": "^5.1",
"symfony/asset": "^4.0",
"symfony/console": "^4.0",
"symfony/dotenv": "^4.0",
"symfony/expression-language": "^4.0",
"symfony/flex": "^1.0",
"symfony/form": "^4.0",
"symfony/framework-bundle": "^4.0",
"symfony/lts": "^4@dev",
"symfony/monolog-bundle": "^3.1",
"symfony/orm-pack": "^1.0",
"symfony/profiler-pack": "^1.0",
"symfony/security-bundle": "^4.0",
"symfony/security-csrf": "^4.0",
"symfony/swiftmailer-bundle": "^3.1",
"symfony/thanks": "^1.0",
"symfony/translation": "^4.0",
"symfony/twig-bundle": "^4.0",
"symfony/validator": "^4.0",
"symfony/webpack-encore-pack": "^1.0",
"symfony/yaml": "^4.0",
"twig/extensions": "^1.5",
"white-october/pagerfanta-bundle": "^1.1"
},
"require-dev": {
"sensio/generator-bundle": "~3.0",
"symfony/phpunit-bridge": "^3.0",
"squizlabs/php_codesniffer": "3.*",
"phpunit/phpunit": "^6"
},
"scripts": {
"post-install-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
],
"post-update-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
]
"dama/doctrine-test-bundle": "^5.0",
"doctrine/doctrine-fixtures-bundle": "^3.0",
"friendsofphp/php-cs-fixer": "^2.10",
"phpunit/phpunit": "^7.0",
"squizlabs/php_codesniffer": "^3.2",
"symfony/browser-kit": "^4.0",
"symfony/css-selector": "^4.0",
"symfony/debug-pack": "^1.0",
"symfony/maker-bundle": "^1.0",
"symfony/phpunit-bridge": "^4.0",
"symfony/web-server-bundle": "^4.0"
},
"config": {
"bin-dir": "bin"
"preferred-install": {
"*": "dist"
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php56": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony-app-dir": "app",
"symfony-bin-dir": "bin",
"symfony-var-dir": "var",
"symfony-web-dir": "web",
"symfony-tests-dir": "tests",
"symfony-assets-install": "relative",
"incenteev-parameters": {
"file": "app/config/parameters.yml",
"env-map": {
"database_url": "DATABASE_URL",
"secret": "SYMFONY_SECRET"
}
"symfony": {
"id": "01C3FWRDJJEX9K6Y3A4XDFXPBR",
"allow-contrib": false
}
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/kevinpapst/AdminThemeBundle"
}
]
}

5551
composer.lock generated

File diff suppressed because it is too large Load Diff

21
config/bundles.php Normal file
View File

@@ -0,0 +1,21 @@
<?php
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true],
Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
Avanzu\AdminThemeBundle\AvanzuAdminThemeBundle::class => ['all' => true],
WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
];

View File

@@ -0,0 +1,9 @@
avanzu_admin_theme:
use_twig: true
use_assetic: false
bower_bin: "/usr/local/bin/bower"
options:
default_avatar: build/images/default_avatar.png
control_sidebar: true
knp_menu:
enable: false

View File

@@ -0,0 +1,16 @@
services:
EasyCorp\EasyLog\EasyLogHandler:
public: false
arguments: ['%kernel.logs_dir%/%kernel.environment%.log']
#// FIXME: How to add this configuration automatically without messing up with the monolog configuration?
#monolog:
# handlers:
# buffered:
# type: buffer
# handler: easylog
# channels: ['!event']
# level: debug
# easylog:
# type: service
# id: EasyCorp\EasyLog\EasyLogHandler

View File

@@ -0,0 +1,19 @@
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]

View File

@@ -0,0 +1,3 @@
framework:
router:
strict_requirements: true

View File

@@ -0,0 +1,4 @@
# See https://symfony.com/doc/current/email/dev_environment.html
swiftmailer:
# send all emails to a specific address
#delivery_addresses: ['me@example.com']

View File

@@ -0,0 +1,6 @@
web_profiler:
toolbar: true
intercept_redirects: false
framework:
profiler: { only_exceptions: false }

View File

@@ -0,0 +1,27 @@
parameters:
# Adds a fallback DATABASE_URL if the env var is not set.
# This allows you to run cache:warmup even if your
# environment variables are not available yet.
# You should not need to change this value.
env(DATABASE_URL): ''
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
# With Symfony 3.3, remove the `resolve:` prefix
url: '%env(resolve:DATABASE_URL)%'
orm:
auto_generate_proxy_classes: '%kernel.debug%'
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Kimai

View File

@@ -0,0 +1,5 @@
doctrine_migrations:
dir_name: '%kernel.project_dir%/src/Migrations'
# namespace is arbitrary but should be different from App\Migrations
# as migrations classes should NOT be autoloaded
namespace: DoctrineMigrations

View File

@@ -0,0 +1,34 @@
framework:
secret: '%env(APP_SECRET)%'
default_locale: en
csrf_protection: ~
#http_method_override: true
# Enables session support. Note that the session will ONLY be started if you read or write from it.
# Remove or comment this section to explicitly disable session support.
session:
handler_id: session.handler.native_file
save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%"
#esi: ~
#fragments: ~
php_errors:
log: true
cache:
# The app cache caches to the filesystem by default. Other options include:
# Redis
#app: cache.adapter.redis
#default_redis_provider: redis://localhost
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
#app: cache.adapter.apcu
#available with Symfony 4.1
#validation:
# possible values: 'loose', 'strict', 'html5'
#email_validation_mode: 'html5'
assets:
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'

View File

@@ -0,0 +1,50 @@
kimai:
# All configs related to timesheet and record management
timesheet:
# Whether we display start and end time columns (false) or durations only (true).
# Setting this to true will also change the "edit timesheet" forms, more infos available in the configurations docu.
duration_only: false
# Rounding rules are used to round the begin & end dates and the duration for timesheet records.
# The "default" rule will round "begin" down and "end" up to the full minute, the "duration" will not be rounded.
# Please read var/docs/configurations.md to find out more about rounding rules
rounding:
default:
days: ['monday','tuesday','wednesday','thursday','friday','saturday','sunday']
begin: 1
end: 1
duration: 0
# If you want to apply different hourly rates for specific weekdays, you can uncomment the "rates" configuration.
# The "weekend" rule will add 50% to each timesheet entry that will be recorded on "saturdays" or "sundays".
# Please read var/docs/configurations.md to find out more about rates rules
# rates:
# weekend:
# days: ['saturday','sunday']
# factor: 1.5
# All configs related to the invoice administration
invoice:
renderer:
default: 'App\Controller\InvoiceController::invoiceAction'
timesheet: 'App\Controller\InvoiceController::timesheetAction'
calculator:
default: 'App\Invoice\DefaultCalculator'
short: 'App\Invoice\ShortInvoiceCalculator'
number_generator:
default: 'App\Invoice\DateNumberGenerator'
twig:
globals:
kimai_context:
date_1: "d.m.Y" # used for display in timesheets
box_color: "green" # a color for ???
active_warning: 3 # display a warning color if the user has at least X active recordings
control_sidebar: # all tabs in the control sidebar
settings:
icon: gears
controller: 'App\Controller\SidebarController::settingsAction'
home:
icon: question-circle-o
template: sidebar/home.html.twig

View File

@@ -0,0 +1,31 @@
doctrine:
orm:
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
services:
doctrine.result_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.result_cache_pool'
doctrine.system_cache_provider:
class: Symfony\Component\Cache\DoctrineProvider
public: false
arguments:
- '@doctrine.system_cache_pool'
framework:
cache:
pools:
doctrine.result_cache_pool:
adapter: cache.app
doctrine.system_cache_pool:
adapter: cache.system

View File

@@ -0,0 +1,17 @@
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_404s:
# regex: exclude all 404 errors from the logs
- ^/
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]

View File

@@ -0,0 +1,3 @@
framework:
router:
strict_requirements: ~

View File

@@ -1,28 +1,34 @@
security:
encoders:
# Our user class and the algorithm we'll use to encode passwords
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
AppBundle\Entity\User: bcrypt
App\Entity\User: bcrypt
# https://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
# in this example, users are stored via Doctrine in the database
# demo users can be found at src/AppBundle/DataFixtures/ORM/LoadFixtures.php
database_users:
entity: { class: AppBundle:User, property: username }
entity:
class: App\Entity\User
# http://symfony.com/doc/current/book/security.html#firewalls-authentication
firewalls:
secured_area:
# does what it says
logout_on_user_change: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
# this firewall applies to all URLs
pattern: ^/
# make sure only allowed users have access to their time-tracking
user_checker: App\Security\UserChecker
# but the firewall does not require login on every page
# denying access is done in access_control or in your controllers
anonymous: ~
remember_me:
secret: '%kernel.secret%'
lifetime: 604800
path: /
# This allows the user to login by submitting a username and password
# Reference: http://symfony.com/doc/current/cookbook/security/form_login_setup.html
form_login:
@@ -53,3 +59,4 @@ security:
- { path: '^/(%app_locales%)$', role: IS_AUTHENTICATED_FULLY }
- { path: '^/(%app_locales%)/login', role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: '^/(%app_locales%)/admin', roles: ROLE_ADMIN }

View File

@@ -0,0 +1,3 @@
swiftmailer:
url: '%env(MAILER_URL)%'
spool: { type: 'memory' }

View File

@@ -0,0 +1,4 @@
framework:
test: ~
session:
storage_id: session.storage.mock_file

View File

@@ -0,0 +1,7 @@
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]

View File

@@ -0,0 +1,11 @@
# this configuration simplifies testing URLs protected by the security mechanism
# See https://symfony.com/doc/current/cookbook/testing/http_authentication.html
security:
encoders:
# to make tests much faster, BCrypt cost is changed to its minimum allowed value (4)
# See https://symfony.com/doc/current/reference/configuration/security.html#using-the-bcrypt-password-encoder
App\Entity\User: { algorithm: bcrypt, cost: 4 }
firewalls:
secured_area:
http_basic: ~

View File

@@ -0,0 +1,2 @@
swiftmailer:
disable_delivery: true

View File

@@ -0,0 +1,6 @@
web_profiler:
toolbar: false
intercept_redirects: false
framework:
profiler: { collect: false }

View File

@@ -0,0 +1,5 @@
framework:
default_locale: '%locale%'
translator:
fallbacks:
- 'en'

View File

@@ -0,0 +1,4 @@
twig:
#paths: ['%kernel.project_dir%/templates']
debug: '%kernel.debug%'
strict_variables: '%kernel.debug%'

View File

@@ -0,0 +1,12 @@
services:
_defaults:
public: false
autowire: true
autoconfigure: true
#Twig\Extensions\ArrayExtension: ~
#Twig\Extensions\DateExtension: ~
Twig\Extensions\IntlExtension: ~
#Twig\Extensions\TextExtension: ~
Twig\Extensions\StringLoader:
class: Twig_Extension_StringLoader

18
config/routes.yaml Normal file
View File

@@ -0,0 +1,18 @@
home:
path: /
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
route: homepage
permanent: true
homepage:
path: /{_locale}
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
route: timesheet
permanent: true
avanzu_admin_profile:
path: /{_locale}/profile/{username}
options:
avanzu_admin_route: profile

View File

@@ -0,0 +1,8 @@
controllers:
resource: '../src/Controller/'
type: annotation
prefix: /{_locale}
requirements:
_locale: '%app_locales%'
defaults:
_locale: '%locale%'

View File

@@ -0,0 +1,8 @@
# ========================================================================
# Demo routes, only work with "avanzu_admin_theme/enable_demo: true"
# ========================================================================
#avanzu_admin:
# prefix: /admin
# resource: "@AvanzuAdminThemeBundle/Resources/config/routes.yml"

View File

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

View File

@@ -0,0 +1,7 @@
web_profiler_wdt:
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
prefix: /_wdt
web_profiler_profiler:
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
prefix: /_profiler

95
config/services.yaml Normal file
View File

@@ -0,0 +1,95 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en
app_locales: en|de|ru
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
bind:
$projectDirectory: "%kernel.project_dir%"
$durationOnly: "%kimai.timesheet.duration_only%"
# 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/{Entity,Migrations,Tests}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
# ================================================================================
# APPLICATION CORE
# ================================================================================
App\Invoice\ServiceInvoice:
class: App\Invoice\ServiceInvoice
arguments: ['%kimai.invoice%']
# a route listener, that injects the default locale into the route
App\EventSubscriber\RedirectToLocaleSubscriber:
class: App\EventSubscriber\RedirectToLocaleSubscriber
arguments: ['@router', '%app_locales%', '%locale%']
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
# ================================================================================
# DATABASE
# ================================================================================
# service that prefixes every database table
App\Doctrine\TablePrefixSubscriber:
class: App\Doctrine\TablePrefixSubscriber
arguments: ["%env(resolve:DATABASE_PREFIX)%"]
tags:
- { name: doctrine.event_subscriber }
# updates timesheet records and apply configured rate & rounding rules
App\Doctrine\TimesheetSubscriber:
class: App\Doctrine\TimesheetSubscriber
arguments: [!tagged timesheet.calculator]
tags:
- { name: doctrine.event_listener, event: prePersist, lazy: true }
- { name: doctrine.event_listener, event: preUpdate, lazy: true }
# ================================================================================
# FORMS
# ================================================================================
# form type to edit user roles
App\Form\Type\UserRoleType:
class: App\Form\Type\UserRoleType
arguments: ["%security.role_hierarchy.roles%"]
tags:
- { name: form.type }
App\Form\Extension\DocumentationLinkExtension:
tags:
- { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }
# ================================================================================
# THEME
# ================================================================================
App\Twig\Extensions:
arguments: ['%app_locales%']
# ================================================================================
# TIMESHEET RECORD CALCULATOR
# ================================================================================
App\Timesheet\Calculator\DurationCalculator:
arguments: ["%kimai.timesheet.rounding%"]
App\Timesheet\Calculator\RateCalculator:
arguments: ["%kimai.timesheet.rates%"]

View File

@@ -0,0 +1,9 @@
services:
_defaults:
public: true
# If you need to access services in a test, create an alias
# and then fetch that alias from the container. As a convention,
# aliases are prefixed with test. For example:
#
# test.App\Service\MyService: '@App\Service\MyService'

23
package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"scripts": {
"dev-server": "./node_modules/.bin/encore dev-server",
"dev": "./node_modules/.bin/encore dev",
"watch": "./node_modules/.bin/encore dev --watch",
"build": "./node_modules/.bin/encore production",
"prod": "node_modules/.bin/encore production"
},
"devDependencies": {
"@symfony/webpack-encore": "^0.20.1",
"bootstrap-sass": "^3.3.7",
"bootstrap-select": "^1.13.1",
"daterangepicker": "^3.0.3",
"font-awesome": "^4.7.0",
"icheck": "^1.0.2",
"jquery": "^3.3.1",
"jquery-slimscroll": "^1.3.8",
"jquery-ui": "^1.12.1",
"node-sass": "^4.9.0",
"sass-loader": "^7.0.2",
"webpack-notifier": "^1.5.1"
}
}

View File

@@ -2,30 +2,53 @@
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="app/autoload.php"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<server name="KERNEL_DIR" value="app/" />
<ini name="intl.default_locale" value="en_US" />
<env name="KERNEL_CLASS" value="App\Kernel" />
<env name="APP_ENV" value="test"/>
<env name="APP_DEBUG" value="1"/>
<env name="APP_SECRET" value="5a79a1c866efef9ca1800f971d689f3e"/>
<env name="DATABASE_PREFIX" value="kimai2_"/>
<!-- define your env variables for the test env here -->
<!-- ###+ doctrine/doctrine-bundle ### -->
<env name="DATABASE_URL" value="sqlite:///var/data/kimai_test.sqlite"/>
<!-- ###- doctrine/doctrine-bundle ### -->
<!-- ###+ symfony/swiftmailer-bundle ### -->
<env name="MAILER_URL" value="null://localhost"/>
<!-- ###- symfony/swiftmailer-bundle ### -->
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>src/*Bundle/Tests</directory>
<testsuite name="Kimai">
<directory>tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src/</directory>
<directory suffix=".php">templates/</directory>
<exclude>
<directory>src/*Bundle/Resources</directory>
<directory>src/*/*Bundle/Resources</directory>
<directory>src/*/Bundle/*Bundle/Resources</directory>
<directory suffix=".php">public/</directory>
<directory suffix=".php">tests/</directory>
<directory suffix=".php">var/</directory>
<directory suffix=".php">vendor/</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
<listeners>
<!-- it begins a database transaction before every testcase and rolls it back after
the test finished, so tests can manipulate the database without affecting other tests -->
<listener class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitListener" />
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
</phpunit>

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

25
public/build/app.css Normal file

File diff suppressed because one or more lines are too long

86
public/build/app.js Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

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