Showing preview only (635K chars total). Download the full file or copy to clipboard to get everything.
Repository: techdev-solutions/trackr-backend
Branch: development
Commit: f985c5f16ee6
Files: 245
Total size: 553.9 KB
Directory structure:
gitextract_0tzlhsw6/
├── .gitignore
├── LICENSE
├── README.md
├── application.yaml
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
├── main/
│ ├── java/
│ │ └── de/
│ │ └── techdev/
│ │ └── trackr/
│ │ ├── Trackr.java
│ │ ├── core/
│ │ │ ├── mail/
│ │ │ │ ├── GMailConfiguration.java
│ │ │ │ ├── MailService.java
│ │ │ │ └── support/
│ │ │ │ ├── AsyncMailService.java
│ │ │ │ └── NoOpJavaMailSender.java
│ │ │ ├── pdf/
│ │ │ │ ├── HtmlPdfConverter.java
│ │ │ │ ├── PdfCreationException.java
│ │ │ │ ├── PdfRenderer.java
│ │ │ │ └── ThymeleafRenderer.java
│ │ │ ├── security/
│ │ │ │ ├── AuthorityService.java
│ │ │ │ ├── InMemoryAuthorityService.java
│ │ │ │ ├── InMemorySecurityConfiguration.java
│ │ │ │ ├── MethodSecurityConfiguration.java
│ │ │ │ ├── OAuth2AuthorityService.java
│ │ │ │ └── OAuth2ResourceServerConfiguration.java
│ │ │ └── web/
│ │ │ ├── api/
│ │ │ │ ├── ApiRepositoryRestConfiguration.java
│ │ │ │ ├── ApiWebMvcConfiguration.java
│ │ │ │ ├── ArgumentResolverPagingAndSortingTemplateVariables.java
│ │ │ │ ├── ExceptionHandlers.java
│ │ │ │ ├── JsonMappingHandlerExceptionResolver.java
│ │ │ │ └── RepositoryEntityLinksWithoutProjection.java
│ │ │ └── converters/
│ │ │ └── DateConverter.java
│ │ ├── domain/
│ │ │ ├── ApiBeansConfiguration.java
│ │ │ ├── common/
│ │ │ │ ├── EmployeeSettingsLocaleResolver.java
│ │ │ │ ├── FederalState.java
│ │ │ │ ├── FederalStateController.java
│ │ │ │ └── UuidMapper.java
│ │ │ ├── company/
│ │ │ │ ├── Address.java
│ │ │ │ ├── AddressEventHandler.java
│ │ │ │ ├── AddressRepository.java
│ │ │ │ ├── Company.java
│ │ │ │ ├── CompanyEventHandler.java
│ │ │ │ ├── CompanyRepository.java
│ │ │ │ ├── CompanyWithAddressAndContactPersonsProjection.java
│ │ │ │ ├── ContactPerson.java
│ │ │ │ ├── ContactPersonEventHandler.java
│ │ │ │ └── ContactPersonRepository.java
│ │ │ ├── employee/
│ │ │ │ ├── Employee.java
│ │ │ │ ├── EmployeeController.java
│ │ │ │ ├── EmployeeEventHandler.java
│ │ │ │ ├── EmployeeRepository.java
│ │ │ │ ├── EmployeeScheduledJob.java
│ │ │ │ ├── Projections.java
│ │ │ │ ├── SelfEmployee.java
│ │ │ │ ├── SelfEmployeeRepository.java
│ │ │ │ ├── Settings.java
│ │ │ │ ├── SettingsRepository.java
│ │ │ │ ├── addressbook/
│ │ │ │ │ ├── AddressBookController.java
│ │ │ │ │ └── EmployeeForAddressBookDTO.java
│ │ │ │ ├── expenses/
│ │ │ │ │ ├── TravelExpense.java
│ │ │ │ │ ├── TravelExpenseEventHandler.java
│ │ │ │ │ ├── TravelExpenseRepository.java
│ │ │ │ │ ├── TravelExpenseTypeController.java
│ │ │ │ │ └── reports/
│ │ │ │ │ ├── Projections.java
│ │ │ │ │ ├── Report.java
│ │ │ │ │ ├── ReportController.java
│ │ │ │ │ ├── ReportEventHandler.java
│ │ │ │ │ ├── ReportNotifyService.java
│ │ │ │ │ ├── ReportRepository.java
│ │ │ │ │ ├── ReportService.java
│ │ │ │ │ └── comments/
│ │ │ │ │ ├── Comment.java
│ │ │ │ │ ├── CommentEventHandler.java
│ │ │ │ │ ├── CommentRepository.java
│ │ │ │ │ └── CommentWithEmployeeProjection.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── PrincipalController.java
│ │ │ │ │ └── support/
│ │ │ │ │ └── SupervisorService.java
│ │ │ │ ├── sickdays/
│ │ │ │ │ ├── SickDays.java
│ │ │ │ │ ├── SickDaysEventHandler.java
│ │ │ │ │ ├── SickDaysNotifyService.java
│ │ │ │ │ ├── SickDaysRepository.java
│ │ │ │ │ └── SickDaysWithEmployeeProjection.java
│ │ │ │ ├── vacation/
│ │ │ │ │ ├── Holiday.java
│ │ │ │ │ ├── HolidayCalculator.java
│ │ │ │ │ ├── HolidayRepository.java
│ │ │ │ │ ├── VacationRequest.java
│ │ │ │ │ ├── VacationRequestApproveService.java
│ │ │ │ │ ├── VacationRequestController.java
│ │ │ │ │ ├── VacationRequestEventHandler.java
│ │ │ │ │ ├── VacationRequestRepository.java
│ │ │ │ │ ├── VacationRequestScheduledJobs.java
│ │ │ │ │ ├── VacationRequestWithEmployeeAndApproverProjection.java
│ │ │ │ │ └── support/
│ │ │ │ │ ├── MailApproveService.java
│ │ │ │ │ ├── MessageWrapper.java
│ │ │ │ │ ├── VacationRequestEmployeeToDaysTotalService.java
│ │ │ │ │ └── VacationRequestNotifyService.java
│ │ │ │ └── worktimetracking/
│ │ │ │ └── WorkTimeTrackingReminderService.java
│ │ │ ├── project/
│ │ │ │ ├── Project.java
│ │ │ │ ├── ProjectEventHandler.java
│ │ │ │ ├── ProjectRepository.java
│ │ │ │ ├── ProjectWithCompanyAndDebitorProjection.java
│ │ │ │ ├── billtimes/
│ │ │ │ │ ├── BillableTime.java
│ │ │ │ │ ├── BillableTimeController.java
│ │ │ │ │ ├── BillableTimeEventHandler.java
│ │ │ │ │ ├── BillableTimeRepository.java
│ │ │ │ │ └── BillableTimeWithProjectProjection.java
│ │ │ │ ├── invoice/
│ │ │ │ │ ├── ChangeStateService.java
│ │ │ │ │ ├── Invoice.java
│ │ │ │ │ ├── InvoiceController.java
│ │ │ │ │ ├── InvoiceEventHandler.java
│ │ │ │ │ ├── InvoiceOverdueService.java
│ │ │ │ │ ├── InvoiceRepository.java
│ │ │ │ │ ├── InvoiceScheduledJob.java
│ │ │ │ │ └── InvoiceWithDebitorProjection.java
│ │ │ │ └── worktimes/
│ │ │ │ ├── CustomWorkTime.java
│ │ │ │ ├── Projections.java
│ │ │ │ ├── WorkTime.java
│ │ │ │ ├── WorkTimeController.java
│ │ │ │ ├── WorkTimeEmployee.java
│ │ │ │ ├── WorkTimeEventHandler.java
│ │ │ │ └── WorkTimeRepository.java
│ │ │ ├── scheduling/
│ │ │ │ ├── LastWorkdayDayOfMonthTrigger.java
│ │ │ │ └── ScheduledJobsConfiguration.java
│ │ │ ├── translations/
│ │ │ │ └── TranslationController.java
│ │ │ └── validation/
│ │ │ ├── EndAfterBeginValidator.java
│ │ │ ├── ProjectBelongsToCompanyValidator.java
│ │ │ └── constraints/
│ │ │ ├── EndAfterBegin.java
│ │ │ └── ProjectBelongsToCompany.java
│ │ └── util/
│ │ └── LocalDateUtil.java
│ └── resources/
│ ├── META-INF/
│ │ └── mail-integration.xml
│ ├── banner.txt
│ ├── data.sql
│ ├── db/
│ │ └── migration/
│ │ ├── V10__modify_travel_expense_add_comment.sql
│ │ ├── V11__add_travel_expense_report_comments.sql
│ │ ├── V12__modify_company_add_time_for_payment.sql
│ │ ├── V13__modify_travel_expense_reports_add_debitor_and_project.sql
│ │ ├── V14__add_uuid_mapping.sql
│ │ ├── V15__migrate_credentials.sql
│ │ ├── V16__add_holidays_2015.sql
│ │ ├── V17__add_holidays_2015.sql
│ │ ├── V18__expense_paid_marker.sql
│ │ ├── V19__add_employee_address.sql
│ │ ├── V1__create_schema.sql
│ │ ├── V20__add_employe_deleted.sql
│ │ ├── V2__add_roles.sql
│ │ ├── V3__add_holidays_2014.sql
│ │ ├── V4__add_invoices.sql
│ │ ├── V5__modify_vacationrequests.sql
│ │ ├── V6__modify_travel_expense_reports_and_contact_persons.sql
│ │ ├── V7__update_travel_expense_report_submission_date_from_travel_expenses.sql
│ │ ├── V8__add_sick_days.sql
│ │ └── V9__modify_travel_expense_report.sql
│ ├── i18n/
│ │ ├── trackr-de.json
│ │ ├── trackr-en.json
│ │ └── validation/
│ │ ├── messages_de.properties
│ │ └── messages_en.properties
│ ├── logback-console.xml
│ ├── logback-file.xml
│ └── pdfTemplates/
│ └── travel-expenses/
│ └── report.html
└── test/
├── java/
│ └── de/
│ └── techdev/
│ ├── test/
│ │ ├── FlywayTest.java
│ │ ├── InMemoryOAuth2ResourceServerConfiguration.java
│ │ ├── TestConstants.java
│ │ ├── TransactionalIntegrationTest.java
│ │ ├── oauth/
│ │ │ ├── OAuthRequest.java
│ │ │ └── OAuthTestExecutionListener.java
│ │ └── rest/
│ │ ├── AbstractDomainResourceSecurityTest.java
│ │ ├── AbstractJsonGenerator.java
│ │ ├── AbstractRestIntegrationTest.java
│ │ ├── DomainResourceTestMatchers.java
│ │ └── TestRestTemplate.java
│ └── trackr/
│ ├── core/
│ │ └── web/
│ │ └── converters/
│ │ └── DateConverterTest.java
│ └── domain/
│ ├── common/
│ │ ├── FederalStateControllerIntegrationTest.java
│ │ ├── UuidMapperIntegrationTest.java
│ │ └── UuidMapperTest.java
│ ├── company/
│ │ ├── AddressJsonGenerator.java
│ │ ├── AddressResourceSecurityTest.java
│ │ ├── CompanyJsonGenerator.java
│ │ ├── CompanyRepositoryTest.java
│ │ ├── CompanyResourceSecurityTest.java
│ │ ├── ContactPersonJsonGenerator.java
│ │ └── ContactPersonResourceSecurityTest.java
│ ├── employee/
│ │ ├── EmployeeControllerSecurityTest.java
│ │ ├── EmployeeJsonGenerator.java
│ │ ├── EmployeeResourceIntegrationTest.java
│ │ ├── EmployeeResourceSecurityTest.java
│ │ ├── SelfEmployeeRepositoryTest.java
│ │ ├── addressbook/
│ │ │ ├── AddressBookControllerSecurityTest.java
│ │ │ └── AddressBookControllerTest.java
│ │ ├── expenses/
│ │ │ ├── TravelExpenseJsonGenerator.java
│ │ │ ├── TravelExpenseResourceSecurityTest.java
│ │ │ └── report/
│ │ │ ├── ReportJsonGenerator.java
│ │ │ ├── ReportResourceSecurityTest.java
│ │ │ ├── ReportServiceTest.java
│ │ │ └── comment/
│ │ │ ├── CommentJsonGenerator.java
│ │ │ └── CommentResourceSecurityTest.java
│ │ ├── login/
│ │ │ └── PrincipalControllerSecurityTest.java
│ │ ├── sickdays/
│ │ │ ├── SickDaysJsonGenerator.java
│ │ │ └── SickDaysResourceSecurityTest.java
│ │ ├── vacation/
│ │ │ ├── HolidayCalculatorTest.java
│ │ │ ├── HolidayResourceTest.java
│ │ │ ├── VacationRequestControllerSecurityTest.java
│ │ │ ├── VacationRequestJsonGenerator.java
│ │ │ ├── VacationRequestRepositoryTest.java
│ │ │ ├── VacationRequestResourceSecurityTest.java
│ │ │ ├── VacationRequestScheduledJobsTest.java
│ │ │ └── support/
│ │ │ ├── MailApproveServiceTest.java
│ │ │ ├── MessageWrapperTest.java
│ │ │ ├── VacationRequestEmployeeToDaysTotalServiceTest.java
│ │ │ └── VacationRequestNotifyServiceTest.java
│ │ └── worktimetracking/
│ │ └── WorkTimeTrackingReminderServiceIntegrationTest.java
│ ├── project/
│ │ ├── ProjectJsonGenerator.java
│ │ ├── ProjectResourceSecurityTest.java
│ │ ├── billtimes/
│ │ │ ├── BillableTimeControllerIntegrationTest.java
│ │ │ ├── BillableTimeResourceSecurityTest.java
│ │ │ └── BillableTimesJsonGenerator.java
│ │ ├── invoice/
│ │ │ ├── InvoiceEventHandlerTest.java
│ │ │ ├── InvoiceJsonGenerator.java
│ │ │ └── InvoiceResourceSecurityTest.java
│ │ └── worktimes/
│ │ ├── CustomWorkTimeTest.java
│ │ ├── WorkTimeControllerSecurityTest.java
│ │ ├── WorkTimeControllerTest.java
│ │ ├── WorkTimeJsonGenerator.java
│ │ ├── WorkTimeRepositoryTest.java
│ │ └── WorkTimeResourceSecurityTest.java
│ ├── scheduling/
│ │ └── LastWorkdayDayOfMonthTriggerTest.java
│ └── translations/
│ ├── TranslationControllerSecurityTest.java
│ └── TranslationControllerTest.java
└── resources/
└── de/
└── techdev/
└── trackr/
└── domain/
├── company/
│ ├── address/
│ │ └── resourceTest.sql
│ ├── contactPerson/
│ │ └── resourceTest.sql
│ ├── repositoryTest.sql
│ └── resourceTest.sql
├── employee/
│ ├── expenses/
│ │ ├── report/
│ │ │ ├── comment/
│ │ │ │ └── resourceTest.sql
│ │ │ └── resourceTest.sql
│ │ └── resourceTest.sql
│ ├── login/
│ │ └── resourceTest.sql
│ ├── resourceTest.sql
│ ├── sickdays/
│ │ └── resourceTest.sql
│ └── vacation/
│ ├── holiday/
│ │ └── resourceTest.sql
│ ├── repositoryTest.sql
│ └── resourceTest.sql
├── emptyDatabase.sql
├── project/
│ ├── billtimes/
│ │ └── resourceTest.sql
│ ├── invoice/
│ │ └── resourceTest.sql
│ ├── resourceTest.sql
│ └── worktimes/
│ ├── repositoryTest.sql
│ └── resourceTest.sql
└── tableUuidMapping.sql
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# OS
application.pid
# gradle / Maven
target/
build/
.gradle/
# IDEA
.idea/
*.iml
*.ipr
atlassian-ide-plugin.xml
# Eclipse
.settings/
.project
# OSX
.DS_Store
/.nb-gradle/private/
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2014 techdev Solutions UG http://techdev.de
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
trackr backend
==============
What is it?
-------------
trackr is an application to track petty much everything that is going on in your company.
Keep track of vacations, sick days, invoices and many more.
trackr comes with a Java-based backend and a [frontend](https://github.com/techdev-solutions/trackr-frontend) written in AngularJS. This project is the Java/Spring based
backend, a stateless REST API with either OAuth2 or basic authentication.
You can read all about trackr in our developer blog:
* [Architecture and Backend](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-i/)
* [Testing](http://blog.techdev.de/testing-a-secured-spring-data-rest-service-with-java-8-and-mockmvc/)
* [Mail Approvals with Spring Integration](http://blog.techdev.de/mail-approvals-with-spring-integration/)
* [Frontend](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-ii/)
* [File Downloads with AngularJS](http://blog.techdev.de/an-angularjs-directive-to-download-pdf-files/)
* [Processes and Tools](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-iii/)
For the API documentation just go [here](http://techdev-solutions.github.io/trackr-api-documentation/getting_started.html).
There is also a [Vagrant](https://www.vagrantup.com/) project building the whole application over [here](https://github.com/techdev-solutions/trackr-vagrant).
How to start
------------
If you just want to mess around with the API a bit the default configuration is very sensible and has no external dependencies (well, except Java).
If you have gradle, just run
gradle run
If you don't have gradle and want to use the wrapper run
./gradlew run
# or
gradlew.bat run
If you want to start from your IDE, i.e. for debugging open the class `Trackr` and start the main method.
To verify it works you can use curl. The users don't have a password in this configuration, so just press enter when curl asks for one. If you don't like the usernames
change them in import.sql.
curl --user moritz.schulze@techdev.de localhost:8080
The default config uses port 8080, if that is used on your system you can add
server:
port: $port
to the top of the application.yaml and choose a port that you want for `$port`.
Profiles
--------
trackr has a lot of Spring profiles to add/switch features.
| profile | description | notes |
|--------------------|------------------------------------------------------------|------------------------------------------------------------------|
| in-memory-database | uses a H2 database, creates the schema with hibernate | excluse with real-database |
| real-database | uses a configurable database, executes flyway | exclusive with in-memory-database |
| http-basic | protects the API with HTTP basic authentication | exclusive with oauth |
| oauth | protects the API as a OAuth2 resource server | exclusive with http-basic. Database for OAuth2 tokens needed. |
| granular-security | roles and per endpoint security | |
| gmail | sends mail with Gmail and enables mail receiving | when off, does not receive mails and uses a logging mail sender. |
| dev | initialize the database with data.sql | |
| prod | Just some different settings for our production env | |
Take a look in the application.yaml to see what properties these profiles need.
The default profiles are `in-memory-database,dev,granular-security,http-basic`. If you want to use other profiles, there are several possible ways.
1. You can change the `spring.profiles.active` value in application.yaml
2. If you use `gradle run` you can prepend (example) `SPRING_PROFILES_ACTIVE=dev,gmail,real-database`. You can also use this to overwrite e.g. the port with `SERVER_PORT=8000`.
3. If you run from your IDE, you can add `--spring.profiles.active=dev,gmail,real-database` as program arguments to the run configuration.
Please refer to the [Spring Boot Reference](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/) for more information.
### The oauth profile
The oauth profile marks the trackr backend as a OAuth2 resource server, that means access is only possible with a valid access token issued by an authorization server. We use a
JDBC token store, so valid tokens need to be put there. Please take a look at our (soon to be open sourced) techdev portal to see how we do this.
### The granular-security profile
When this is not selected, to access the API the user needs to be authenticated. With granular security the access to some endpoints depend on the role of the user or even the
id of the user. In trackr, the id of a user is the email address of the belonging employee.
When the oauth profile is switched off, all users have the role ROLE_ADMIN. When oauth is on, the roles must be stored in the access token.
Take a look at the `@PreAuthorize` and `@PostAuthorize` annotations in the code to see what this will activate.
How to build
------------
Just run
gradle build
(or use the wrapper if you don't have gradle installed). The JAR file will be in `build/libs` and can just be run with `java -jar`. The application.yaml file has to be in the
working directory where the `java` command was issued.
================================================
FILE: application.yaml
================================================
spring:
jpa:
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
datasource:
initialize: false
profiles:
active: in-memory-database,dev,granular-security,http-basic
trackr:
frontendUrl: http://localhost
logging:
config: classpath:logback-console.xml
---
spring:
profiles: prod
trackr:
frontendUrl:
logging:
config: classpath:logback-file.xml
---
spring:
profiles: dev
datasource:
initialize: true
---
spring:
profiles: real-database
jpa:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
ddl-auto: validate
datasource:
driverClassName: org.postgresql.Driver
url: jdbc:postgresql://127.0.0.1:5432/trackr
username:
password:
flyway:
schemas: public
---
spring:
profiles: in-memory-database
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:trackr;DB_CLOSE_DELAY\=-1
username: sa
password:
jpa:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
ddl-auto: create
flyway:
enabled: false
---
spring:
profiles: oauth
trackr:
database:
oauth:
driverClassName: org.postgresql.Driver
url: jdbc:postgresql://127.0.0.1:5432/techdev_oauth
username:
password:
---
spring:
profiles: gmail
mail:
host: smtp.gmail.com
port: 465
username:
password:
properties:
mail.smtp.auth: true
mail.smtp.starttls.enable: true
mail.transport.protocol: smtp
mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
================================================
FILE: build.gradle
================================================
plugins {
id 'org.springframework.boot' version '1.5.19.RELEASE'
}
apply plugin: 'java'
apply plugin: 'jacoco'
sourceCompatibility = 1.8
compileJava.options.encoding = 'UTF-8'
// Options for naming the JAR file
archivesBaseName = 'trackr-backend'
version = '1.0'
if(project.hasProperty('teamcity')) {
version += '-build-' + project.teamcity['build.number']
} else {
version += '-localbuild'
}
repositories {
mavenCentral()
}
springBoot {
executable = true
}
dependencies {
compile "org.springframework.boot:spring-boot-starter-data-rest"
compile "org.springframework.boot:spring-boot-starter-data-jpa"
compile "org.springframework.boot:spring-boot-starter-mail"
compile "org.springframework.boot:spring-boot-starter-integration"
compile "org.springframework.boot:spring-boot-starter-security"
// not included in boot
compile "org.springframework.integration:spring-integration-mail:4.2.5.RELEASE"
compile "org.springframework.security.oauth:spring-security-oauth2"
compile "com.h2database:h2"
compile "org.postgresql:postgresql"
compile "org.flywaydb:flyway-core"
compile("org.xhtmlrenderer:flying-saucer-pdf-itext5:9.0.6")
compile("org.thymeleaf:thymeleaf")
compileOnly "org.projectlombok:lombok:1.12.4"
testCompileOnly "org.projectlombok:lombok:1.12.4"
annotationProcessor "org.projectlombok:lombok:1.12.4"
testAnnotationProcessor "org.projectlombok:lombok:1.12.4"
compile "org.glassfish:javax.json:1.0"
// Not included by default for Spring Boot 1.5
compile "commons-io:commons-io:2.1"
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile("org.echocat.jomon:testing:1.4.3") {
exclude group: "org.mockito"
}
testCompile "org.mockito:mockito-core:1.9.5"
testCompile "com.jayway.jsonpath:json-path"
testCompile "org.apache.httpcomponents:httpclient"
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Jan 23 09:44:57 CET 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-bin.zip
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: src/main/java/de/techdev/trackr/Trackr.java
================================================
package de.techdev.trackr;
import org.springframework.boot.ApplicationPid;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Primary;
import java.io.File;
import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@SpringBootApplication(exclude = MailSenderAutoConfiguration.class)
@ImportResource(value = "classpath:META-INF/mail-integration.xml")
public class Trackr {
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@PostConstruct
private void handlePid() throws IOException {
File file = new File("application.pid");
new ApplicationPid().write(file);
file.deleteOnExit();
}
public static void main(String[] args) {
SpringApplication.run(Trackr.class, args);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/mail/GMailConfiguration.java
================================================
package de.techdev.trackr.core.mail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import java.util.Map;
import java.util.Properties;
import javax.mail.Session;
/**
* This configuration class is mostly copied from {@link org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration}.
*
* Since we need to expose the {@link #mailSession()} for our {@code mail-integration.xml} to work and the Spring autoconfig
* class creates a circular dependency (JavaMailSender <-> Session) we have to use the relevant parts ourselves.
*/
@Configuration
@EnableConfigurationProperties(MailProperties.class)
@Profile("gmail")
public class GMailConfiguration {
@Autowired
private MailProperties properties;
@Bean
public JavaMailSenderImpl mailSender() {
JavaMailSenderImpl sender = new JavaMailSenderImpl();
applyProperties(sender);
return sender;
}
private void applyProperties(JavaMailSenderImpl sender) {
sender.setHost(this.properties.getHost());
if (this.properties.getPort() != null) {
sender.setPort(this.properties.getPort());
}
sender.setUsername(this.properties.getUsername());
sender.setPassword(this.properties.getPassword());
sender.setProtocol(this.properties.getProtocol());
if (this.properties.getDefaultEncoding() != null) {
sender.setDefaultEncoding(this.properties.getDefaultEncoding().name());
}
if (!this.properties.getProperties().isEmpty()) {
sender.setJavaMailProperties(asProperties(this.properties.getProperties()));
}
}
private Properties asProperties(Map<String, String> source) {
Properties properties = new Properties();
properties.putAll(source);
return properties;
}
/**
* We expose the mail session as a bean for the Spring Integration mail receiver.
*/
@Bean
public Session mailSession() {
return mailSender().getSession();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/mail/MailService.java
================================================
package de.techdev.trackr.core.mail;
import org.springframework.mail.SimpleMailMessage;
/**
* @author Moritz Schulze
*/
public interface MailService {
void sendMail(SimpleMailMessage mailMessage);
}
================================================
FILE: src/main/java/de/techdev/trackr/core/mail/support/AsyncMailService.java
================================================
package de.techdev.trackr.core.mail.support;
import de.techdev.trackr.core.mail.MailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.mail.MailMessage;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Component;
/**
* Puts the mail message into a queue to be sent by Spring Integration.
*/
@Component
public class AsyncMailService implements MailService {
@Autowired
@Qualifier("mailSendChannel")
private MessageChannel mailChannel;
@Override
public void sendMail(SimpleMailMessage mailMessage) {
Message<MailMessage> asyncMessage = new GenericMessage<>(mailMessage);
mailChannel.send(asyncMessage);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/mail/support/NoOpJavaMailSender.java
================================================
package de.techdev.trackr.core.mail.support;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Profile;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Component;
import javax.mail.internet.MimeMessage;
import java.io.InputStream;
import java.util.Arrays;
@Slf4j
@Profile("!gmail")
@Component("mailSender")
public class NoOpJavaMailSender implements JavaMailSender {
@Override
public MimeMessage createMimeMessage() {
log.debug("Create mime message");
return null;
}
@Override
public MimeMessage createMimeMessage(InputStream contentStream) {
log.debug("Create Mime message with stream");
return null;
}
@Override
public void send(MimeMessage mimeMessage) {
log.debug("Send single mime message");
}
@Override
public void send(MimeMessage[] mimeMessages) {
log.debug("Send multiple mime messages");
}
@Override
public void send(MimeMessagePreparator mimeMessagePreparator) {
log.debug("Send mime message preparator");
}
@Override
public void send(MimeMessagePreparator[] mimeMessagePreparators) {
log.debug("Send multiple mime message preparators");
}
@Override
public void send(SimpleMailMessage simpleMessage) {
StringBuilder builder = new StringBuilder("Send simple mail message..\n");
builder
.append("From: ").append(simpleMessage.getFrom()).append("\n")
.append("To: ").append(Arrays.toString(simpleMessage.getTo())).append("\n")
.append("Subject: ").append(simpleMessage.getSubject()).append("\n")
.append("--------------------------------------------").append("\n")
.append(simpleMessage.getText());
log.debug(builder.toString());
}
@Override
public void send(SimpleMailMessage[] simpleMessages) {
log.debug("Send multiple simple messages");
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/pdf/HtmlPdfConverter.java
================================================
package de.techdev.trackr.core.pdf;
import com.itextpdf.text.DocumentException;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @author Moritz Schulze
*/
public class HtmlPdfConverter {
private ITextRenderer renderer;
public HtmlPdfConverter() {
renderer = new ITextRenderer();
//This can be used to set a font?
// ITextFontResolver fontResolver = renderer.getFontResolver();
// ClassPathResource regular = new ClassPathResource("/META-INF/fonts/LiberationSerif-Regular.ttf");
// fontResolver.addFont(regular.getURL().toString(), BaseFont.IDENTITY_H, true);
}
public byte[] renderHtmlToPdf(String htmlContent) throws PdfCreationException {
renderer.setDocumentFromString(htmlContent);
renderer.layout();
byte[] pdfAsByteArray;
try(ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
renderer.createPDF(bos);
pdfAsByteArray = bos.toByteArray();
} catch (DocumentException | IOException e) {
throw new PdfCreationException(e);
}
return pdfAsByteArray;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/pdf/PdfCreationException.java
================================================
package de.techdev.trackr.core.pdf;
/**
* @author Moritz Schulze
*/
public class PdfCreationException extends Exception {
public PdfCreationException(Exception e) {
super(e);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/pdf/PdfRenderer.java
================================================
package de.techdev.trackr.core.pdf;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.thymeleaf.context.Context;
import javax.annotation.PostConstruct;
/**
* @author Moritz Schulze
*/
@Slf4j
public class PdfRenderer {
// @Value("${pdf.templatePath:META-INF/pdfTemplates}")
@Value("pdfTemplates/")
private String templatePath;
// @Value("${pdf.templateSuffix:pdf.templateSuffix:.html}")
@Value(".html")
private String templateSuffix;
private ThymeleafRenderer thymeleafRenderer;
private HtmlPdfConverter htmlPdfConverter;
public PdfRenderer() {
htmlPdfConverter = new HtmlPdfConverter();
}
@PostConstruct
public void setUpRenderer() {
thymeleafRenderer = new ThymeleafRenderer(templatePath, templateSuffix);
}
public byte[] renderPdf(String templateName, Context context) throws PdfCreationException {
log.debug("Rendering template {}", templateName);
String htmlContent = thymeleafRenderer.renderTemplateToHtml(templateName, context);
return htmlPdfConverter.renderHtmlToPdf(htmlContent);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/pdf/ThymeleafRenderer.java
================================================
package de.techdev.trackr.core.pdf;
import lombok.extern.slf4j.Slf4j;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
/**
* Renders a thymeleaf template as a String containing HTML.
*
* @author Moritz Schulze
*/
@Slf4j
public class ThymeleafRenderer {
private TemplateEngine templateEngine;
private String templatePath;
private String templateSuffix;
public ThymeleafRenderer(String templatePath, String templateSuffix) {
this.templatePath = templatePath;
this.templateSuffix = templateSuffix;
setUpTemplateEngine();
}
private void setUpTemplateEngine() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
log.debug("Configuring template resolver with: path {}, suffix {}", templatePath, templateSuffix);
templateResolver.setPrefix(templatePath);
templateResolver.setSuffix(templateSuffix);
templateResolver.setTemplateMode("XHTML");
templateResolver.setCharacterEncoding("UTF-8");
this.templateEngine = new TemplateEngine();
this.templateEngine.setTemplateResolver(templateResolver);
}
/**
* Render the given template to HTML with the context.
*
* @param templateName The template to render.
* @param context The context to use when rendering the template.
* @return The HTML content of the rendered template as a String.
*/
public String renderTemplateToHtml(String templateName, Context context) {
return templateEngine.process(templateName, context);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/AuthorityService.java
================================================
package de.techdev.trackr.core.security;
import java.util.Collection;
/**
* Access GrantedAuthorities for Employees and emails by GrantedAuthorities
*/
public interface AuthorityService {
/**
* Get all email addresses from employees who have the given authority.
*/
Collection<String> getEmployeeEmailsByAuthority(String authority);
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/InMemoryAuthorityService.java
================================================
package de.techdev.trackr.core.security;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.stream.Collectors;
@Service
@Profile("!oauth")
public class InMemoryAuthorityService implements AuthorityService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public Collection<String> getEmployeeEmailsByAuthority(String authority) {
return employeeRepository.findAllForAddressBook(new PageRequest(0, 100)).getContent().stream().map(Employee::getEmail).collect(Collectors.toList());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/InMemorySecurityConfiguration.java
================================================
package de.techdev.trackr.core.security;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import static java.util.Arrays.asList;
/**
* This configuration enables HTTP Basic authentication and uses the employees as credentials, all with no password and admin access.
*
* It is only enabled when the oauth profile is off.
*/
@EnableWebSecurity
@Configuration
@Profile("http-basic")
public class InMemorySecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private EmployeeRepository employeeRepository;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(username -> {
Employee employee = employeeRepository.findByEmail(username);
if (employee == null) {
throw new BadCredentialsException("User not found");
}
return new User(username, "", asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
}
);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests().anyRequest().fullyAuthenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName("trackr development realm")
.and()
.csrf().disable();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/MethodSecurityConfiguration.java
================================================
package de.techdev.trackr.core.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.access.vote.RoleHierarchyVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
/**
* This class enables global method security via {@link org.springframework.security.access.prepost.PreAuthorize} in JPA Repositories
* and other controllers. It also enables the role hierarchy in them.
*/
@Profile("granular-security")
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext applicationContext;
/**
* This is needed so {@link org.springframework.security.access.prepost.PreAuthorize} and so on know the role hierarchy.
*/
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();
methodSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
//Needs to be done so we can access beans in security expressions
methodSecurityExpressionHandler.setApplicationContext(applicationContext);
return methodSecurityExpressionHandler;
}
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
//TODO make this configurable
roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_SUPERVISOR ROLE_SUPERVISOR > ROLE_EMPLOYEE ROLE_EMPLOYEE > ROLE_ANONYMOUS");
return roleHierarchy;
}
@Bean
public RoleVoter roleVoter() {
return new RoleHierarchyVoter(roleHierarchy());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/OAuth2AuthorityService.java
================================================
package de.techdev.trackr.core.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Profile;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Collection;
@Service
@Profile("oauth")
public class OAuth2AuthorityService implements AuthorityService {
private JdbcTemplate jdbcTemplate;
@Autowired
public OAuth2AuthorityService(@Qualifier("oauthDataSource") DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Collection<String> getEmployeeEmailsByAuthority(String authority) {
return jdbcTemplate.queryForList("SELECT username FROM authorities WHERE authority = ?", String.class, authority);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/security/OAuth2ResourceServerConfiguration.java
================================================
package de.techdev.trackr.core.security;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
import java.util.Collections;
@Profile("oauth")
@EnableWebSecurity
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String TRACKR_RESOURCE_ID = "techdev-services";
@Bean
@Qualifier("oauthDataSource")
@ConfigurationProperties(prefix = "trackr.database.oauth")
public DataSource oauthDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(oauthDataSource());
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(TRACKR_RESOURCE_ID).tokenStore(tokenStore());
}
@Override
public void configure(HttpSecurity http) throws Exception {
User anonymousUser =
new User("anonymous", "EMPTY", Collections.singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS")));
http
.anonymous()
.principal(anonymousUser)
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // since this is just a REST API we don't need a state.
.and().requestMatchers().antMatchers("/**")
.and().authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
.antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
.antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')");
http.headers().addHeaderWriter((request, response) -> {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
if (request.getMethod().equals("OPTIONS")) {
response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
}
});
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/ApiRepositoryRestConfiguration.java
================================================
package de.techdev.trackr.core.web.api;
import de.techdev.trackr.core.web.converters.DateConverter;
import de.techdev.trackr.domain.company.Address;
import de.techdev.trackr.domain.company.Company;
import de.techdev.trackr.domain.company.ContactPerson;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.expenses.TravelExpense;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import de.techdev.trackr.domain.employee.expenses.reports.comments.Comment;
import de.techdev.trackr.domain.employee.sickdays.SickDays;
import de.techdev.trackr.domain.employee.vacation.VacationRequest;
import de.techdev.trackr.domain.project.Project;
import de.techdev.trackr.domain.project.billtimes.BillableTime;
import de.techdev.trackr.domain.project.invoice.Invoice;
import de.techdev.trackr.domain.project.worktimes.WorkTime;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class ApiRepositoryRestConfiguration extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Employee.class, Company.class, ContactPerson.class,
Address.class, Project.class, WorkTime.class, BillableTime.class, VacationRequest.class, TravelExpense.class,
Report.class, Comment.class, Invoice.class, SickDays.class);
config.setReturnBodyOnUpdate(true);
config.setReturnBodyOnCreate(true);
}
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
super.configureConversionService(conversionService);
conversionService.addConverter(dateConverter());
}
@Bean
public DateConverter dateConverter() {
return new DateConverter();
}
/**
* Add the validator to spring data rest.
*/
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("beforeSave", validator());
validatingListener.addValidator("beforeCreate", validator());
}
/**
* Custom validator that extracts messages with locale. Used by spring-data-rest.
*/
@Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(messageSource());
return localValidatorFactoryBean;
}
/**
* Load all messages, reload when locale changes.
*/
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:org/hibernate/validator/ValidationMessages", "classpath:/i18n/validation/messages");
return messageSource;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/ApiWebMvcConfiguration.java
================================================
package de.techdev.trackr.core.web.api;
import de.techdev.trackr.core.web.converters.DateConverter;
import de.techdev.trackr.domain.common.EmployeeSettingsLocaleResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.LocaleResolver;
import java.util.List;
@Configuration
public class ApiWebMvcConfiguration extends RepositoryRestMvcConfiguration {
@Autowired
private DateConverter dateConverter;
/**
* The self HREF for entities contains {?projection} to indicate the parameter is available, but we don't want that.
* The {@link RepositoryEntityLinksWithoutProjection} switches {?projection} off.
*/
@Override
@Bean
public RepositoryEntityLinks entityLinks() {
ArgumentResolverPagingAndSortingTemplateVariables variables = new ArgumentResolverPagingAndSortingTemplateVariables(this.pageableResolver(), this.sortResolver());
return new RepositoryEntityLinksWithoutProjection(repositories(), resourceMappings(), config(), variables, backendIdConverterRegistry());
}
@Bean
public LocaleResolver localeResolver() {
return new EmployeeSettingsLocaleResolver();
}
@Override
public void addFormatters(FormatterRegistry registry) {
// super call is needed so the DomainClassConverter is used for linked resources
// (e.g. companies/0/address). The super class will configure the DomainClassConverter correctly only with this
// super call.
super.addFormatters(registry);
// We need to add the converter so non-Spring-Data-REST calls also use it.
registry.addConverter(dateConverter);
}
/**
* Needed for mapping exceptions in jackson that otherwise would get an ugly error message.
*/
@Bean
public JsonMappingHandlerExceptionResolver jsonMappingHandlerExceptionResolver() {
return new JsonMappingHandlerExceptionResolver();
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(jsonMappingHandlerExceptionResolver());
super.extendHandlerExceptionResolvers(exceptionResolvers);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/ArgumentResolverPagingAndSortingTemplateVariables.java
================================================
package de.techdev.trackr.core.web.api;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;
import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver;
import org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver;
import org.springframework.hateoas.TemplateVariables;
import org.springframework.util.Assert;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Copy from Spring because thankfully they made it package protected. Nice!
*
* @deprecated See {@link RepositoryEntityLinksWithoutProjection}
*/
@Deprecated
class ArgumentResolverPagingAndSortingTemplateVariables implements PagingAndSortingTemplateVariables {
private static final Set<Class<?>> SUPPORTED_TYPES = Collections.unmodifiableSet(new HashSet(Arrays.asList(new Class[]{Pageable.class, Sort.class})));
private final HateoasPageableHandlerMethodArgumentResolver pagingResolver;
private final HateoasSortHandlerMethodArgumentResolver sortResolver;
public ArgumentResolverPagingAndSortingTemplateVariables(HateoasPageableHandlerMethodArgumentResolver pagingResolver, HateoasSortHandlerMethodArgumentResolver sortResolver) {
Assert.notNull(pagingResolver, "HateoasPageableHandlerMethodArgumentResolver must not be null!");
Assert.notNull(sortResolver, "HateoasSortHandlerMethodArgumentResolver must not be null!");
this.pagingResolver = pagingResolver;
this.sortResolver = sortResolver;
}
public TemplateVariables getPaginationTemplateVariables(MethodParameter parameter, UriComponents components) {
return this.pagingResolver.getPaginationTemplateVariables(parameter, components);
}
public TemplateVariables getSortTemplateVariables(MethodParameter parameter, UriComponents template) {
return this.sortResolver.getSortTemplateVariables(parameter, template);
}
public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) {
if(value instanceof Pageable) {
this.pagingResolver.enhance(builder, parameter, value);
} else if(value instanceof Sort) {
this.sortResolver.enhance(builder, parameter, value);
}
}
public boolean supportsParameter(MethodParameter parameter) {
return SUPPORTED_TYPES.contains(parameter.getParameterType());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/ExceptionHandlers.java
================================================
package de.techdev.trackr.core.web.api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.data.rest.core.RepositoryConstraintViolationException;
import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CONFLICT;
/**
* @author Moritz Schulze
*/
@ControllerAdvice
@Slf4j
public class ExceptionHandlers {
private final MessageSourceAccessor messageSourceAccessor;
@Autowired
public ExceptionHandlers(MessageSource messageSource) {
this.messageSourceAccessor = new MessageSourceAccessor(messageSource);
}
/**
* This exception handler <i>should</i> handle violations of unique constraints.
* TODO: JpaSystemException is really broad, we need to check somehow that this only gets invoked for unique constraint violations
* @param e The exception to handle
* @return An error message
*/
@ExceptionHandler(JpaSystemException.class)
@ResponseBody
@ResponseStatus(CONFLICT)
public String handleJpaSystemException(JpaSystemException e) {
return e.getMostSpecificCause().getMessage();
}
/**
* This is for custom controllers (i.e. not spring-data-rest) that do validation.
* @param ex The {@link org.springframework.data.rest.core.RepositoryConstraintViolationException} thrown by the controller.
* @return A map of fieldnames to FieldErrors
*/
@ResponseBody
@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(RepositoryConstraintViolationException.class)
public RepositoryConstraintViolationExceptionMessage handleRepositoryConstraintViolationException(RepositoryConstraintViolationException ex) {
return new RepositoryConstraintViolationExceptionMessage(ex, messageSourceAccessor);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/JsonMappingHandlerExceptionResolver.java
================================================
package de.techdev.trackr.core.web.api;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.json.Json;
import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonGeneratorFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import static java.util.stream.Collectors.reducing;
/**
* Custom exception handler for exceptions thrown while JSON mapping by Jackson. They appear not to be handled by {@link org.springframework.web.bind.annotation.ControllerAdvice}
* exception handlers.
*
* @author Moritz Schulze
*/
public class JsonMappingHandlerExceptionResolver implements HandlerExceptionResolver {
protected JsonGeneratorFactory jsonGeneratorFactory;
public JsonMappingHandlerExceptionResolver() {
jsonGeneratorFactory = Json.createGeneratorFactory(null);
}
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (HttpMessageNotReadableException.class.isAssignableFrom(ex.getClass()) &&
ex.getCause() != null && InvalidFormatException.class.isAssignableFrom(ex.getCause().getClass())) {
Writer outputWriter;
try {
outputWriter = response.getWriter();
} catch (IOException e) {
throw new IllegalStateException("Could not open response writer", e);
}
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.setHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE);
writeExceptionAsJsonToOutput((InvalidFormatException) ex.getCause(), outputWriter);
try {
outputWriter.flush();
outputWriter.close();
} catch (IOException e) {
throw new IllegalStateException("Could not flush and close response writer", e);
}
return new ModelAndView();
}
return null;
}
/**
* Writes the information in the exception as a JSON object like this: { "employee.salary": { "defaultMessage": "Cannot construct float from this value"}}
* to a writer.
*
* @param ex The exception thrown by Jackson
* @param writer The output writer to write to.
*/
protected void writeExceptionAsJsonToOutput(InvalidFormatException ex, Writer writer) {
JsonGenerator jsonGenerator = jsonGeneratorFactory.createGenerator(writer);
jsonGenerator.writeStartObject()
.writeStartArray("errors")
.writeStartObject()
.write("property", getFieldPath(ex))
.write("message", ex.getOriginalMessage())
.writeEnd() //object in array
.writeEnd() //array
.writeEnd().close();
}
/**
* Appends all fieldNames in the path of the exception to a string connected with dots.
*
* @param ex The exception containing the path information
* @return E.g. "employee.firstName"
*/
private String getFieldPath(InvalidFormatException ex) {
return ex.getPath().stream().collect(
reducing(null, //start value
JsonMappingException.Reference::getFieldName, //mapping of one Reference
(s, s2) -> s == null ? s2 : s + "." + s2) //concatenate two strings, prohibit dot at the start of the result
);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/api/RepositoryEntityLinksWithoutProjection.java
================================================
package de.techdev.trackr.core.web.api;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.ResourceMappings;
import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
import org.springframework.hateoas.Link;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Overrides the {@link #linkToSingleResource(Class, Object)} method to not include {?projection}.
* @author Moritz Schulze
* @deprecated We really should make the frontend not rely on this and just remove it all together. For the migration to
* Spring Boot 1.3.3 it's left in so the REST API is as before as much as possible.
*/
@Deprecated
public class RepositoryEntityLinksWithoutProjection extends RepositoryEntityLinks {
private final ResourceMappings mappings;
private final PluginRegistry<BackendIdConverter, Class<?>> idConverters;
/**
* Creates a new {@link org.springframework.data.rest.webmvc.support.RepositoryEntityLinks}.
*
* @param repositories must not be {@literal null}.
* @param mappings must not be {@literal null}.
* @param config must not be {@literal null}.
* @param variables must not be {@literal null}.
* @param idConverters must not be {@literal null}.
*/
public RepositoryEntityLinksWithoutProjection(Repositories repositories, ResourceMappings mappings, RepositoryRestConfiguration config, PagingAndSortingTemplateVariables variables, PluginRegistry<BackendIdConverter, Class<?>> idConverters) {
super(repositories, mappings, config, variables, idConverters);
this.mappings = mappings;
this.idConverters = idConverters;
}
@Override
public Link linkToSingleResource(Class<?> type, Object id) {
Assert.isInstanceOf(Serializable.class, id, "Id must be assignable to Serializable!");
ResourceMetadata metadata = mappings.getMetadataFor(type);
String mappedId = idConverters.getPluginFor(type, BackendIdConverter.DefaultIdConverter.INSTANCE).toRequestId((Serializable) id, type);
return linkFor(type).slash(mappedId).withRel(metadata.getItemResourceRel());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/core/web/converters/DateConverter.java
================================================
package de.techdev.trackr.core.web.converters;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* A {@link java.util.Date} converter that supports the formats yyyy-MM-dd and yyyy-MM-dd HH:mm:ss.
*
* @author Moritz Schulze
*/
public class DateConverter implements Converter<String, Date> {
private DateFormat date10;
private DateFormat date19;
public DateConverter() {
date10 = new SimpleDateFormat("yyyy-MM-dd");
date19 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
@Override
public Date convert(String source) {
if(source == null) {
return null;
}
Date date;
try {
Long milliSeconds = Long.valueOf(source);
return new Date(milliSeconds);
} catch (NumberFormatException e) {
//Continue with other formats
}
if(source.length() == 10) {
try {
date = date10.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException(String.format("%s is not a valid yyyy-MM-dd date.", source), e);
}
} else if(source.length() == 19) {
try {
date = date19.parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException(String.format("%s is not a valid yyyy-MM-dd HH:mm:ss date.", source), e);
}
} else {
throw new IllegalArgumentException(String.format("%s is not convertible by this Date converter", source));
}
return date;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/ApiBeansConfiguration.java
================================================
package de.techdev.trackr.domain;
import de.techdev.trackr.core.pdf.PdfRenderer;
import de.techdev.trackr.domain.common.UuidMapper;
import de.techdev.trackr.domain.employee.expenses.reports.ReportNotifyService;
import de.techdev.trackr.domain.employee.expenses.reports.ReportService;
import de.techdev.trackr.domain.employee.login.support.SupervisorService;
import de.techdev.trackr.domain.employee.sickdays.SickDaysNotifyService;
import de.techdev.trackr.domain.employee.vacation.HolidayCalculator;
import de.techdev.trackr.domain.employee.vacation.VacationRequestApproveService;
import de.techdev.trackr.domain.employee.vacation.support.VacationRequestEmployeeToDaysTotalService;
import de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;
import de.techdev.trackr.domain.employee.worktimetracking.WorkTimeTrackingReminderService;
import de.techdev.trackr.domain.project.invoice.ChangeStateService;
import de.techdev.trackr.domain.project.invoice.InvoiceOverdueService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
/**
* All Beans needed for the API that have nothing to do with web.
*/
@Configuration
@ComponentScan(includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = RepositoryEventHandler.class)
})
public class ApiBeansConfiguration {
@Bean
public ReportService travelExpenseReportService() {
return new ReportService();
}
@Bean
public ReportNotifyService travelExpenseReportNotifyService() {
return new ReportNotifyService();
}
@Bean
public WorkTimeTrackingReminderService workTimeTrackingReminderService() {
return new WorkTimeTrackingReminderService();
}
@Bean
public VacationRequestNotifyService vacationRequestNotifyService() {
return new VacationRequestNotifyService();
}
@Bean
public VacationRequestApproveService vacationRequestService() {
return new VacationRequestApproveService();
}
@Bean
public VacationRequestEmployeeToDaysTotalService vacationRequestEmployeeToDaysTotalService() {
return new VacationRequestEmployeeToDaysTotalService();
}
@Bean
public HolidayCalculator holidayCalculator() {
return new HolidayCalculator();
}
@Bean
public InvoiceOverdueService invoiceOverdueService() {
return new InvoiceOverdueService();
}
@Bean
public ChangeStateService changeStateService() {
return new ChangeStateService();
}
@Bean
public SickDaysNotifyService sickDaysNotifyService() {
return new SickDaysNotifyService();
}
@Bean
public SupervisorService supervisorService() {
return new SupervisorService();
}
@Bean
public PdfRenderer pdfRenderer() {
return new PdfRenderer();
}
@Bean
public UuidMapper uuidMapper() {
return new UuidMapper();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/common/EmployeeSettingsLocaleResolver.java
================================================
package de.techdev.trackr.domain.common;
import de.techdev.trackr.domain.employee.Settings;
import de.techdev.trackr.domain.employee.SettingsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.servlet.LocaleContextResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.util.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class EmployeeSettingsLocaleResolver implements LocaleContextResolver {
@Autowired
private SettingsRepository settingsRepository;
@Override
public Locale resolveLocale(HttpServletRequest request) {
return getLocaleFromSessionOrAuthentication(request);
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
if(locale != null) {
WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
}
@Override
public LocaleContext resolveLocaleContext(HttpServletRequest request) {
final Locale locale = getLocaleFromSessionOrAuthentication(request);
LocaleContext localeContext = () -> locale;
LocaleContextHolder.setLocaleContext(localeContext);
return localeContext;
}
@Override
public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
if(localeContext != null) {
Locale locale = localeContext.getLocale();
WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
}
/**
* Tries to extract the locale from the session. If not present it extracts the locale from the logged in user. Defaults to english.
* @param request The request
* @return The extracted locale, default {@link java.util.Locale#ENGLISH}.
*/
protected Locale getLocaleFromSessionOrAuthentication(HttpServletRequest request) {
Locale locale = (Locale) WebUtils.getSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
if(locale == null) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null) {
Object principal = authentication.getPrincipal();
if (User.class.isAssignableFrom(principal.getClass())) {
String username = ((User) principal).getUsername();
Settings localeSetting = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, username);
if (localeSetting != null) {
locale = Locale.forLanguageTag(localeSetting.getValue());
}
}
}
//Either no authentication or admin user
if(locale == null) {
locale = Locale.ENGLISH;
}
WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
LocaleContextHolder.setLocale(locale);
return locale;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/common/FederalState.java
================================================
package de.techdev.trackr.domain.common;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* @author Moritz Schulze
*/
@JsonFormat(shape= JsonFormat.Shape.OBJECT)
public enum FederalState {
BADEN_WUERTTEMBERG("Baden-Württemberg"), BAYERN("Bayern"), BERLIN("Berlin"), BRANDENBURG("Brandenburg"), BREMEN("Bremen"),
HAMBURG("Hamburg"), HESSEN("Hessen"), MECKLENBURG_VORPOMMERN("Mecklenburg-Vorpommern"), NIEDERSACHSEN("Niedersachsen"), NORDRHEIN_WESTFALEN("Nordrhein-Westfalen"),
RHEINLAND_PFALZ("Rheinland-Pfalz"), SAARLAND("Saarland"), SACHSEN("Sachsen"), SACHSEN_ANHALT("Sachsen-Anhalt"), SCHLESWIG_HOLSTEIN("Schleswig-Holstein"), THUERINGEN("Thüringen");
private String state;
FederalState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public String getName() {
return this.toString();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/common/FederalStateController.java
================================================
package de.techdev.trackr.domain.common;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import static java.util.Arrays.asList;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping("/federalStates")
public class FederalStateController {
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public List<FederalState> federalStates() {
return asList(FederalState.values());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/common/UuidMapper.java
================================================
package de.techdev.trackr.domain.common;
import org.springframework.beans.factory.annotation.Autowired;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Moritz Schulze
*/
public class UuidMapper {
public static final Pattern UUID_PATTERN = Pattern.compile("^.*([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}).*$");
@Autowired
private DataSource dataSource;
public String extractUUIDFromString(String input) {
Matcher matcher = UuidMapper.UUID_PATTERN.matcher(input);
if (matcher.matches()) {
return matcher.group(1);
} else {
return null;
}
}
public Long getIdFromUUID(String uuid) {
Long id = null;
try(Connection connection = dataSource.getConnection();
PreparedStatement getIdStatement = connection.prepareStatement("SELECT id FROM uuid_mapping WHERE uuid = ?")) {
getIdStatement.setString(1, uuid);
ResultSet resultSet = getIdStatement.executeQuery();
if (resultSet.next()) {
id = resultSet.getLong(1);
}
} catch (SQLException e) {
// just return null
}
return id;
}
public void deleteUUID(String uuid) {
try(Connection connection = dataSource.getConnection();
PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM uuid_mapping WHERE uuid = ?")) {
deleteStatement.setString(1, uuid);
deleteStatement.execute();
} catch (SQLException e) {
// nothing to do
}
}
public void deleteUUID(Long id) {
try(Connection connection = dataSource.getConnection();
PreparedStatement deleteStatement = connection.prepareStatement("DELETE FROM uuid_mapping WHERE id = ?")) {
deleteStatement.setLong(1, id);
deleteStatement.execute();
} catch (SQLException e) {
// nothing to do
}
}
public UUID createUUID(Long id) {
UUID uuid = UUID.randomUUID();
try(Connection connection = dataSource.getConnection();
PreparedStatement insertStatement = connection.prepareStatement("INSERT INTO uuid_mapping (id, uuid) VALUES (?, ?)")) {
insertStatement.setLong(1, id);
insertStatement.setString(2, uuid.toString());
insertStatement.execute();
} catch (SQLException e) {
return null;
}
return uuid;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/Address.java
================================================
package de.techdev.trackr.domain.company;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
@Entity
@Getter
@Setter
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotEmpty
private String street;
@NotEmpty
private String houseNumber;
@NotEmpty
private String zipCode;
@NotEmpty
private String city;
@NotEmpty
private String country;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/AddressEventHandler.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.rest.core.annotation.HandleBeforeCreate;
import org.springframework.data.rest.core.annotation.HandleBeforeDelete;
import org.springframework.data.rest.core.annotation.HandleBeforeSave;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* This class prevents other users than admins from creating, updating or deleting addresses.
* <p>
* As long as only {@link de.techdev.trackr.domain.company.Company} uses the Address class this is fine, if e.g. {@link de.techdev.trackr.domain.employee.Employee}
* gets an address too this will have to be thought over.
*
* @author Moritz Schulze
*/
@RepositoryEventHandler(Address.class)
@SuppressWarnings("unused")
public class AddressEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkSaveAuthority(Address address) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkUpdateAuthority(Address address) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkDeleteAuthority(Address address) {
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/AddressRepository.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import java.util.List;
/**
* @author Moritz Schulze
*/
public interface AddressRepository extends JpaRepository<Address, Long> {
@Override
@RestResource(exported = false)
List<Address> findAll();
@Override
@RestResource(exported = false)
Page<Address> findAll(Pageable pageable);
@Override
@RestResource(exported = false)
List<Address> findAll(Sort sort);
@Override
@RestResource(exported = false)
void delete(Long aLong);
@Override
@RestResource(exported = false)
void delete(Address entity);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/Company.java
================================================
package de.techdev.trackr.domain.company;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import de.techdev.trackr.domain.project.Project;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* @author Moritz Schulze
*/
@Getter
@Setter
@EqualsAndHashCode(exclude = "contactPersons")
@Entity
@JsonIgnoreProperties({"debitorProjects"})
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotNull
@DecimalMin("0")
@Column(unique = true)
private Long companyId;
@NotEmpty
private String name;
/**
* Full days that the company has to pay their invoices.
*/
private Integer timeForPayment;
@NotNull
@OneToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "address_id")
private Address address;
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "company")
private List<ContactPerson> contactPersons = new ArrayList<>();
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "company")
private List<Project> projects = new ArrayList<>();
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "debitor")
private List<Project> debitorProjects = new ArrayList<>();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyEventHandler.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.List;
/**
* @author Moritz Schulze
*/
@RepositoryEventHandler(Company.class)
@SuppressWarnings("unused")
public class CompanyEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkSaveAuthority(Company company) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkUpdateAuthority(Company company) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkDeleteAuthority(Company company) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void beforeAddContactPerson(Company company, List<ContactPerson> contactPersons) {
}
@HandleBeforeLinkDelete
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void beforeDeleteContactPerson(Company company, Object contactPerson) {
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyRepository.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
/**
* @author Moritz Schulze
*/
@RepositoryRestResource(path = "/companies")
public interface CompanyRepository extends JpaRepository<Company, Long> {
Company findByCompanyId(@Param("companyId") Long companyId);
List<Company> findByNameLikeIgnoreCaseOrderByNameAsc(@Param("name") String name);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyWithAddressAndContactPersonsProjection.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.rest.core.config.Projection;
import java.util.List;
/**
* @author Moritz Schulze
*/
@Projection(types = Company.class, name = "withAddressAndContactPersons")
public interface CompanyWithAddressAndContactPersonsProjection {
Long getId();
Integer getVersion();
Long getCompanyId();
String getName();
Integer getTimeForPayment();
Address getAddress();
List<ContactPerson> getContactPersons();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPerson.java
================================================
package de.techdev.trackr.domain.company;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
public class ContactPerson {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotNull
@ManyToOne
@JoinColumn(name = "company")
private Company company;
@Email
private String email;
@NotEmpty
private String firstName;
@NotEmpty
private String lastName;
private String phone;
@NotEmpty
private String salutation;
private String roles;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPersonEventHandler.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* @author Moritz Schulze
*/
@RepositoryEventHandler(ContactPerson.class)
@SuppressWarnings("unused")
public class ContactPersonEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkCreateAuthority(ContactPerson contactPerson) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkUpdateAuthority(ContactPerson contactPerson) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkDeleteAuthority(ContactPerson contactPerson) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkLinkUpdateAuthority(ContactPerson contactPerson, Object links) {
// only security check
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void checkLinkDeleteAuthority(ContactPerson contactPerson, Object linkedEntity) {
// only security check
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPersonRepository.java
================================================
package de.techdev.trackr.domain.company;
import org.springframework.data.repository.CrudRepository;
/**
* @author Moritz Schulze
*/
public interface ContactPersonRepository extends CrudRepository<ContactPerson, Long> {
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/Employee.java
================================================
package de.techdev.trackr.domain.employee;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import de.techdev.trackr.domain.common.FederalState;
import de.techdev.trackr.domain.company.Address;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import de.techdev.trackr.domain.employee.vacation.VacationRequest;
import de.techdev.trackr.domain.project.billtimes.BillableTime;
import de.techdev.trackr.domain.project.worktimes.WorkTime;
import de.techdev.trackr.domain.validation.constraints.EndAfterBegin;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Represents any employee of techdev.
*/
@Entity
@Getter
@Setter
@JsonIgnoreProperties({"credential", "workTimes", "billableTimes", "vacationRequests", "approvedRequests", "travelExpenseReports"})
@EndAfterBegin(begin = "joinDate", end = "leaveDate")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotEmpty
private String firstName;
@NotEmpty
private String lastName;
@Column(unique = true)
@Email
@NotEmpty
private String email;
private String phoneNumber;
private String title;
private BigDecimal salary;
private BigDecimal hourlyCostRate;
@Temporal(TemporalType.DATE)
private Date joinDate;
@Temporal(TemporalType.DATE)
private Date leaveDate;
@Enumerated(EnumType.STRING)
@NotNull
private FederalState federalState;
private Float vacationEntitlement;
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "employee")
private List<WorkTime> workTimes = new ArrayList<>();
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "employee")
private List<BillableTime> billableTimes = new ArrayList<>();
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "employee")
private List<VacationRequest> vacationRequests;
@OneToMany(mappedBy = "approver")
private List<VacationRequest> approvedRequests;
@OneToMany(mappedBy = "employee")
private List<Report> travelExpenseReports;
@OneToOne(orphanRemoval = true)
private Address address;
private boolean deleted;
public String fullName() {
return getFirstName() + " " + getLastName();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeController.java
================================================
package de.techdev.trackr.domain.employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.core.RepositoryConstraintViolationException;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
/**
* A controller for special operations on Employees not exportable by spring-data-rest
*/
@Controller
@RequestMapping(value = "/employees")
public class EmployeeController {
@Autowired
private SelfEmployeeRepository employeeRepository;
/**
* This method allows an employee to change some values of his entity on his own, namely the one
* in SelfEmployee.
*
* @param employee The employee to edit.
* @param selfEmployee The request body, i.e. the data to change
* @return The updated data.
*/
@ResponseBody
@RequestMapping(value = "/{employee}/self", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public SelfEmployee updateSelf(@PathVariable("employee") Long employee,
@RequestBody @Valid SelfEmployee selfEmployee,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new RepositoryConstraintViolationException(bindingResult);
}
return SelfEmployee.valueOf(employeeRepository.save(employee, selfEmployee));
}
@RequestMapping(value = "/{employee}/self", method = {RequestMethod.GET})
@ResponseBody
public SelfEmployee get(@PathVariable("employee") Long employeeId) {
return employeeRepository.findOne(employeeId);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeEventHandler.java
================================================
package de.techdev.trackr.domain.employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
@RepositoryEventHandler(Employee.class)
@SuppressWarnings("unused")
public class EmployeeEventHandler {
@Autowired
private SettingsRepository settingsRepository;
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkCreateAuthority(Employee employee) {
}
@HandleAfterCreate
public void createInitialSettings(Employee employee) {
Settings settings = new Settings();
settings.setEmployee(employee);
settings.setType(Settings.SettingsType.LOCALE);
settings.setValue("de");
settingsRepository.save(settings);
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkUpdateAuthority(Employee employee) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkDeleteAuthority(Employee employee) {
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void deleteCredentialForbidden(Employee employee, Object credential) {
//deny all, cannot be called
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeRepository.java
================================================
package de.techdev.trackr.domain.employee;
import de.techdev.trackr.domain.common.FederalState;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.List;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Override
@PostAuthorize("hasRole('ROLE_SUPERVISOR') or returnObject?.email == principal?.username")
Employee findOne(@Param("id") Long id);
@Override
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
List<Employee> findAll();
@Override
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
List<Employee> findAll(Sort sort);
@Override
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
List<Employee> findAll(Iterable<Long> longs);
@Override
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
Page<Employee> findAll(Pageable pageable);
@RestResource(exported = false)
List<Employee> findByFederalState(FederalState berlin);
/**
* Not exported find all method to access all employees without the need for SUPERVISOR/ADMIN rights.
*
* Filters the admin out. Only used for the address book.
*/
@RestResource(exported = false)
@Query("select e from Employee e where e.email <> 'admin@techdev.de' and e.deleted = false")
Page<Employee> findAllForAddressBook(Pageable pageable);
@RestResource(exported = false)
Employee findByEmail(String email);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeScheduledJob.java
================================================
package de.techdev.trackr.domain.employee;
import de.techdev.trackr.domain.common.FederalState;
import de.techdev.trackr.domain.employee.worktimetracking.WorkTimeTrackingReminderService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
@Setter
public class EmployeeScheduledJob {
@Autowired
private WorkTimeTrackingReminderService workTimeTrackingReminderService;
/**
* Task that gets triggered in {@link de.techdev.trackr.domain.scheduling.ScheduledJobsConfiguration} by a custom trigger.
*
* @param state The federal state to send out reminders for.
* @return A task that reminds employees in the federal state to track their working times.
*/
public Runnable sendWorkTimeReminderTask(FederalState state) {
return () -> workTimeTrackingReminderService.remindEmployeesToTrackWorkTimes(state);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/Projections.java
================================================
package de.techdev.trackr.domain.employee;
import de.techdev.trackr.domain.common.FederalState;
import de.techdev.trackr.domain.company.Address;
import org.springframework.data.rest.core.config.Projection;
import java.math.BigDecimal;
import java.util.Date;
public class Projections {
@Projection(types = Employee.class, name = "withAddress")
public interface WithAddressProjection {
Long getId();
Integer getVersion();
String getFirstName();
String getLastName();
String getEmail();
String getPhoneNumber();
String getTitle();
BigDecimal getSalary();
BigDecimal getHourlyCostRate();
Date getJoinDate();
Date getLeaveDate();
FederalState getFederalState();
Float getVacationEntitlement();
Address getAddress();
boolean isDeleted();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/SelfEmployee.java
================================================
package de.techdev.trackr.domain.employee;
import de.techdev.trackr.domain.company.Address;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import java.math.BigDecimal;
@Getter
@Setter
public class SelfEmployee {
private Long id;
private Integer version;
@NotEmpty
private String firstName;
@NotEmpty
private String lastName;
private String phoneNumber;
private String title;
private BigDecimal salary;
@Valid
private Address address;
public static SelfEmployee valueOf(Employee employee) {
SelfEmployee selfEmployee = new SelfEmployee();
selfEmployee.setId(employee.getId());
selfEmployee.setFirstName(employee.getFirstName());
selfEmployee.setLastName(employee.getLastName());
selfEmployee.setPhoneNumber(employee.getPhoneNumber());
selfEmployee.setAddress(employee.getAddress());
selfEmployee.setVersion(employee.getVersion());
selfEmployee.setSalary(employee.getSalary());
selfEmployee.setTitle(employee.getTitle());
return selfEmployee;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/SelfEmployeeRepository.java
================================================
package de.techdev.trackr.domain.employee;
import de.techdev.trackr.domain.company.Address;
import de.techdev.trackr.domain.company.AddressRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
public class SelfEmployeeRepository {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private AddressRepository addressRepository;
/**
* Update all values on an employee that an employee is allowed to update him/herself.
* This is the last name, first name, phone number and address.
* @param employeeId The id of the employee to update.
* @param selfEmployee The new data for the employee.
* @return The updated employee
*/
@Transactional
@PostAuthorize("hasRole('ROLE_ADMIN') or returnObject.email == principal?.username")
public Employee save(Long employeeId, SelfEmployee selfEmployee) {
Employee employee = employeeRepository.findOne(employeeId);
employee.setFirstName(selfEmployee.getFirstName());
employee.setLastName(selfEmployee.getLastName());
employee.setPhoneNumber(selfEmployee.getPhoneNumber());
if (selfEmployee.getAddress() != null) {
Address address = addressRepository.save(selfEmployee.getAddress());
employee.setAddress(address);
}
return employeeRepository.save(employee);
}
public SelfEmployee findOne(Long employeeId) {
return SelfEmployee.valueOf(employeeRepository.findOne(employeeId));
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/Settings.java
================================================
package de.techdev.trackr.domain.employee;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
@Entity
@Getter
@Setter
@Table( uniqueConstraints = { @UniqueConstraint(columnNames = {"type", "employee_id"}) } )
public class Settings {
public enum SettingsType {
LOCALE
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Enumerated(EnumType.STRING)
private SettingsType type;
@NotEmpty
private String value;
@ManyToOne
@NotNull
@JoinColumn(name = "employee_id")
private Employee employee;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/SettingsRepository.java
================================================
package de.techdev.trackr.domain.employee;
import org.springframework.data.repository.Repository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import java.util.List;
@RepositoryRestResource(exported = false)
public interface SettingsRepository extends Repository<Settings, Long> {
Settings save(Settings settings);
List<Settings> findByEmployee_Email(String email);
Settings findByTypeAndEmployee_Email(Settings.SettingsType type, String email);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/addressbook/AddressBookController.java
================================================
package de.techdev.trackr.domain.employee.addressbook;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resources;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping("/address_book")
public class AddressBookController {
@Autowired
private EmployeeRepository employeeRepository;
@PreAuthorize("hasRole('ROLE_EMPLOYEE')")
@ResponseBody
@RequestMapping(method = RequestMethod.GET, produces = "application/hal+json")
public Resources<EmployeeForAddressBookDTO> getAddressList(
@PageableDefault(sort = "lastName") Pageable pageable
) {
Page<Employee> pageOfEmployees = employeeRepository.findAllForAddressBook(pageable);
List<EmployeeForAddressBookDTO> employeeForAddressBookDTOs = transformToReducedEmployees(pageOfEmployees.getContent());
return new PagedResources<>(employeeForAddressBookDTOs, pageMetadataFromPage(pageOfEmployees));
}
/**
* Transform a list of employees to a list of reduced employees
*
* @param listOfEmployees The list to transform
* @return The transformed list.
*/
protected List<EmployeeForAddressBookDTO> transformToReducedEmployees(List<Employee> listOfEmployees) {
return listOfEmployees
.stream()
.map(EmployeeForAddressBookDTO::valueOf)
.collect(Collectors.toList());
}
protected PagedResources.PageMetadata pageMetadataFromPage(Page page) {
return new PagedResources.PageMetadata(page.getSize(), page.getNumber(), page.getTotalElements(), page.getTotalPages());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/addressbook/EmployeeForAddressBookDTO.java
================================================
package de.techdev.trackr.domain.employee.addressbook;
import de.techdev.trackr.domain.company.Address;
import de.techdev.trackr.domain.employee.Employee;
import lombok.Getter;
import lombok.Setter;
/**
* Employee only containing the information needed for the address book.
*/
@Getter
@Setter
class EmployeeForAddressBookDTO {
private Long id;
private String firstName;
private String lastName;
private String phoneNumber;
private String title;
private String email;
private Address address;
static EmployeeForAddressBookDTO valueOf(Employee employee) {
EmployeeForAddressBookDTO employeeForAddressBookDTO = new EmployeeForAddressBookDTO();
employeeForAddressBookDTO.setId(employee.getId());
employeeForAddressBookDTO.setFirstName(employee.getFirstName());
employeeForAddressBookDTO.setLastName(employee.getLastName());
employeeForAddressBookDTO.setPhoneNumber(employee.getPhoneNumber());
employeeForAddressBookDTO.setTitle(employee.getTitle());
employeeForAddressBookDTO.setEmail(employee.getEmail());
employeeForAddressBookDTO.setAddress(employee.getAddress());
return employeeForAddressBookDTO;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpense.java
================================================
package de.techdev.trackr.domain.employee.expenses;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import de.techdev.trackr.domain.validation.constraints.EndAfterBegin;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
@Getter
@Setter
@Entity
@EndAfterBegin(begin = "fromDate", end = "toDate")
public class TravelExpense {
public enum Type {
HOTEL, TAXI, FLIGHT, TRAIN, PARKING, OEPNV, MILEAGE_ALLOWANCE, OTHER
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotNull
@ManyToOne
private Report report;
@NotNull
@Enumerated(EnumType.STRING)
private Type type;
@NotNull
private BigDecimal cost;
@NotNull
private BigDecimal vat;
@NotNull
@Temporal(TemporalType.DATE)
private Date fromDate;
@NotNull
@Temporal(TemporalType.DATE)
private Date toDate;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date submissionDate;
private String comment;
private boolean paid;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseEventHandler.java
================================================
package de.techdev.trackr.domain.employee.expenses;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
@RepositoryEventHandler(TravelExpense.class)
@SuppressWarnings("unused")
public class TravelExpenseEventHandler {
@HandleBeforeCreate
@PreAuthorize("@travelExpenseEventHandler.canCreate(principal?.username, #travelExpense)")
public void checkCreateAuthority(TravelExpense travelExpense) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or @travelExpenseEventHandler.canEdit(principal?.username, #travelExpense)")
public void checkUpdateAuthority(TravelExpense travelExpense) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or @travelExpenseEventHandler.canDelete(principal?.username, #travelExpense)")
public void checkDeleteAuthority(TravelExpense travelExpense) {
}
@HandleBeforeLinkSave
@PreAuthorize("denyAll()")
public void denyLinkSave(TravelExpense travelExpense, Object links) {
//links are not settable
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void denyLinkDelete(TravelExpense travelExpense, Object linkedEntity) {
//links are not deletable.
}
public boolean canCreate(String email, TravelExpense travelExpense) {
return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&
travelExpense.getReport().getStatus() != Report.Status.APPROVED &&
travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;
}
public boolean canEdit(String email, TravelExpense travelExpense) {
return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&
travelExpense.getReport().getStatus() != Report.Status.APPROVED &&
travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;
}
public boolean canDelete(String email, TravelExpense travelExpense) {
return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&
travelExpense.getReport().getStatus() != Report.Status.APPROVED &&
travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseRepository.java
================================================
package de.techdev.trackr.domain.employee.expenses;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PostAuthorize;
/**
* @author Moritz Schulze
*/
public interface TravelExpenseRepository extends CrudRepository<TravelExpense, Long> {
@Override
@RestResource(exported = false)
Iterable<TravelExpense> findAll();
@Override
@PostAuthorize("returnObject?.report.employee.email == principal?.username")
TravelExpense findOne(Long aLong);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseTypeController.java
================================================
package de.techdev.trackr.domain.employee.expenses;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import static java.util.Arrays.asList;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping("/travelExpenses")
public class TravelExpenseTypeController {
@ResponseBody
@RequestMapping(value = "types", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<TravelExpense.Type> types() {
return asList(TravelExpense.Type.values());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Projections.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.domain.company.Company;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.expenses.TravelExpense;
import de.techdev.trackr.domain.project.Project;
import org.springframework.data.rest.core.config.Projection;
import java.util.Date;
import java.util.List;
/**
* @author Moritz Schulze
*/
public class Projections {
@Projection(types = Report.class, name = "overview")
public interface TravelExpenseReportForOverviewProjection {
Long getId();
Employee getEmployee();
Report.Status getStatus();
List<TravelExpense> getExpenses();
Date getSubmissionDate();
Date getApprovalDate();
Employee getApprover();
Company getDebitor();
Project getProject();
}
@Projection(types = Report.class, name = "withEmployeeAndExpenses")
public interface TravelExpenseReportWithEmployeeAndTravelExpensesProjection {
Long getId();
Integer getVersion();
Employee getEmployee();
List<TravelExpense> getExpenses();
Report.Status getStatus();
Date getSubmissionDate();
}
@Projection(types = Report.class, name = "withExpensesAndDebitor")
public interface TravelExpenseReportWithExpensesAndDebitorProjection {
Long getId();
Integer getVersion();
List<TravelExpense> getExpenses();
Report.Status getStatus();
Date getSubmissionDate();
Date getApprovalDate();
Company getDebitor();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Report.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.domain.company.Company;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.expenses.TravelExpense;
import de.techdev.trackr.domain.employee.expenses.reports.comments.Comment;
import de.techdev.trackr.domain.project.Project;
import de.techdev.trackr.domain.validation.constraints.ProjectBelongsToCompany;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author Moritz Schulze
*/
@Getter
@Setter
@Entity
@Table(name = "travelExpenseReport")
@ProjectBelongsToCompany(companyField = "debitor")
public class Report {
public enum Status {
SUBMITTED, PENDING, APPROVED, REJECTED
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@ManyToOne
private Employee employee;
@OneToMany(mappedBy = "report", cascade = CascadeType.ALL)
private List<TravelExpense> expenses = new ArrayList<>();
@Enumerated(EnumType.STRING)
private Status status;
@Temporal(TemporalType.TIMESTAMP)
private Date submissionDate;
@Temporal(TemporalType.TIMESTAMP)
private Date approvalDate;
@ManyToOne
private Employee approver;
@OneToMany(mappedBy = "travelExpenseReport", cascade = CascadeType.REMOVE)
private List<Comment> comments;
@ManyToOne(optional = false)
private Company debitor;
@ManyToOne
private Project project;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportController.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.core.pdf.PdfCreationException;
import de.techdev.trackr.core.pdf.PdfRenderer;
import de.techdev.trackr.domain.employee.expenses.TravelExpense;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.context.Context;
import java.math.BigDecimal;
import java.security.Principal;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@Controller
@RequestMapping("/travelExpenseReports")
public class ReportController {
@Autowired
private ReportService travelExpenseReportService;
@Autowired
private PdfRenderer pdfRenderer;
@Autowired
private ReportRepository travelExpenseReportRepository;
@RequestMapping(value = "/{id}/submit", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus(HttpStatus.NO_CONTENT)
public void submit(@PathVariable("id") Report travelExpenseReport) {
travelExpenseReportService.submit(travelExpenseReport);
}
@RequestMapping(value = "/{id}/approve", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus(HttpStatus.NO_CONTENT)
public void approve(@PathVariable("id") Report travelExpenseReport, Principal principal) {
travelExpenseReportService.accept(travelExpenseReport, principal.getName());
}
@RequestMapping(value = "/{id}/reject", method = RequestMethod.PUT)
@ResponseBody
@ResponseStatus(HttpStatus.NO_CONTENT)
public void reject(@PathVariable("id") Report travelExpenseReport, Principal principal) {
travelExpenseReportService.reject(travelExpenseReport, principal.getName());
}
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username")
@RequestMapping(value = "/{id}/pdf", produces = "application/pdf")
@Transactional
public ResponseEntity<byte[]> asPdf(@PathVariable("id") Report travelExpenseReport) {
Report report = travelExpenseReportRepository.findOne(travelExpenseReport.getId());
Context ctx = new Context();
ctx.setVariable("report", report);
ctx.setVariable("today", new Date());
List<TravelExpense> expenses = report.getExpenses();
BigDecimal totalCost = expenses.stream().map(TravelExpense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalReimbursement = expenses.stream()
.filter(te -> !te.isPaid()).map(TravelExpense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
ctx.setVariable("totalCost", totalCost);
ctx.setVariable("totalReimbursement", totalReimbursement);
Optional<Date> startDate = expenses.stream().map(TravelExpense::getFromDate).min(Date::compareTo);
Optional<Date> endDate = expenses.stream().map(TravelExpense::getToDate).max(Date::compareTo);
if (startDate.isPresent()) {
ctx.setVariable("startDate", startDate.get());
}
if(endDate.isPresent()) {
ctx.setVariable("endDate", endDate.get());
}
try {
byte[] pdf = pdfRenderer.renderPdf("travel-expenses/report", ctx);
byte[] pdfBase64 = Base64.encodeBase64(pdf);
return new ResponseEntity<>(pdfBase64, HttpStatus.OK);
} catch (PdfCreationException e) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportEventHandler.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
@RepositoryEventHandler(Report.class)
@SuppressWarnings("unused")
public class ReportEventHandler {
@HandleBeforeCreate
@PreAuthorize("#travelExpenseReport.employee.email == principal?.username")
public void checkCreateAuthority(Report travelExpenseReport) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkUpdateAuthority(Report travelExpenseReport) {
}
@HandleBeforeDelete
@PreAuthorize("@reportEventHandler.employeeCanDeleteReport(#travelExpenseReport, principal?.username) or hasRole('ROLE_ADMIN')")
public void checkDeleteAuthority(Report travelExpenseReport) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username")
public void checkLinkSaveAuthority(Report travelExpenseReport, Object links) {
//TODO: links is the _old_ content of the link
//TODO: how to check for security? the employee should not be able to edit debitor/project but how do we check that?
//TODO: it is not possible to prohibit employees from editing links in general because it is used to add travel expenses.
if (links != null && Employee.class.isAssignableFrom(links.getClass())) {
throw new AccessDeniedException("Employee is not changeable on a travel expense report.");
}
}
@HandleBeforeLinkDelete
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username")
public void checkLinkDeleteAuthority(Report travelExpenseReport, Object linkedEntity) {
if(travelExpenseReport.getEmployee() == null) {
throw new AccessDeniedException("Employee is not deletable on a travel expense report.");
}
}
public boolean employeeCanDeleteReport(Report report, String username) {
return username != null && report.getEmployee().getEmail().equals(username) &&
(report.getStatus() == Report.Status.PENDING || report.getStatus() == Report.Status.REJECTED);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportNotifyService.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.core.mail.MailService;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.expenses.TravelExpense;
import de.techdev.trackr.domain.employee.login.support.SupervisorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
public class ReportNotifyService {
@Autowired
private MailService mailService;
@Autowired
private SupervisorService supervisorService;
@Autowired
private ReportRepository travelExpenseReportRepository;
@Value("${trackr.frontendUrl}")
private String frontendUrl;
/**
* Sends a mail to all supervisors except the owning for a submitted travel expense report.
*
* @param report The report for which the mail is to be sent.
*/
public void notifySupervisorsOnSubmission(Report report) {
String[] emails = supervisorService.getSupervisorEmailsArrayWithout(email ->
!report.getEmployee().getEmail().equals(email)
);
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom("no-reply@techdev.de");
mailMessage.setTo(emails);
mailMessage.setSubject("New travel expense report by " + fullName(report.getEmployee()));
mailMessage.setText(
String.format("%s submitted a new travel expense report (#%d) totalling %.2f.\n\nGo to %s to approve or reject it.",
fullName(report.getEmployee()), report.getId(), getTotalAmount(report), getWebLink(report))
);
mailService.sendMail(mailMessage);
}
protected String getWebLink(Report report) {
return frontendUrl + "/supervisor/expenses/" + report.getId();
}
public void notifyEmployeeOnApproval(Report report) {
notifyEmployeeOnStatusChange(report, "approved");
}
public void notifyEmployeeOnRejection(Report report) {
notifyEmployeeOnStatusChange(report, "rejected");
}
private void notifyEmployeeOnStatusChange(Report report, String outcome) {
SimpleMailMessage mail = new SimpleMailMessage();
mail.setFrom("no-reply@techdev.de");
mail.setTo(report.getEmployee().getEmail());
mail.setSubject(String.format("Your travel expense report has been %s", outcome));
mail.setText(
String.format("%s has %s your travel expense report #%d.",
fullName(report.getApprover()), outcome, report.getId())
);
mailService.sendMail(mail);
}
@Transactional
protected BigDecimal getTotalAmount(Report report) {
// Since the report passed to this method is not attached to the JPA session anymore we have to reload it to get
// the expenses which are lazily fetched.
List<TravelExpense> expenses = travelExpenseReportRepository.findOne(report.getId()).getExpenses();
return expenses.stream()
.map(TravelExpense::getCost)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
protected String fullName(Employee employee) {
return employee.getFirstName() + " " + employee.getLastName();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportRepository.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
import java.util.List;
@RepositoryRestResource(path = "travelExpenseReports")
public interface ReportRepository extends CrudRepository<Report, Long> {
@Override
@RestResource(exported = false)
Iterable<Report> findAll();
@Override
@PostAuthorize("hasRole('ROLE_SUPERVISOR') or returnObject?.employee?.email == principal?.username")
Report findOne(Long aLong);
@PreAuthorize("#employee.email == principal?.username")
Page<Report> findByEmployeeAndStatusOrderByStatusAsc(@Param("employee") Employee employee, @Param("status") Report.Status status, Pageable pageable);
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
Page<Report> findByStatus(@Param("status") Report.Status status, Pageable pageable);
@PreAuthorize("hasRole('ROLE_ADMIN')")
List<Report> findBySubmissionDateBetween(@Param("start") Date start, @Param("end") Date end);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportService.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Transactional
public class ReportService {
@Autowired
private ReportRepository travelExpenseReportRepository;
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private ReportNotifyService travelExpenseReportNotifyService;
@PreAuthorize("#travelExpenseReport.employee.email == principal?.username")
public Report submit(Report travelExpenseReport) {
travelExpenseReportNotifyService.notifySupervisorsOnSubmission(travelExpenseReport);
return setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.SUBMITTED, null);
}
@PreAuthorize("hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.employee.email != principal?.username")
public Report accept(Report travelExpenseReport, String approverName) {
Report acceptedReport = setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.APPROVED, approverName);
travelExpenseReportNotifyService.notifyEmployeeOnApproval(acceptedReport);
return acceptedReport;
}
@PreAuthorize("hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.employee.email != principal?.username")
public Report reject(Report travelExpenseReport, String rejecterName) {
Report rejectedReport = setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.REJECTED, rejecterName);
travelExpenseReportNotifyService.notifyEmployeeOnRejection(rejectedReport);
return rejectedReport;
}
private Report setStatusOnTravelExpenseReport(Report travelExpenseReport, Report.Status status, String approverName) {
if (status == Report.Status.SUBMITTED) {
travelExpenseReport.setSubmissionDate(new Date());
} else {
Employee approver = employeeRepository.findByEmail(approverName);
travelExpenseReport.setApprover(approver);
travelExpenseReport.setApprovalDate(new Date());
}
travelExpenseReport.setStatus(status);
return travelExpenseReportRepository.save(travelExpenseReport);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/Comment.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports.comments;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
@Table(name = "travelExpenseReportComment")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotEmpty
private String text;
@NotNull
@Temporal(TemporalType.TIMESTAMP)
private Date submissionDate;
@ManyToOne
@NotNull
private Report travelExpenseReport;
@ManyToOne
@NotNull
private Employee employee;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentEventHandler.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports.comments;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
@RepositoryEventHandler(value = Comment.class)
@SuppressWarnings("unused")
public class CommentEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or #comment.employee.email == principal?.username")
public void checkCreateAuthority(Comment comment) {
comment.setSubmissionDate(new Date());
}
@HandleBeforeSave
@PreAuthorize("denyAll()")
public void checkUpdateAuthority(Comment comment) {
//deny all
}
@HandleBeforeLinkSave
@PreAuthorize("denyAll()")
public void checkLinkSaveAuthority(Comment comment, Object links) {
//deny all
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void checkLinkDeleteAuthority(Comment comment, Object linkedEntity) {
//deny all
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentRepository.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports.comments;
import de.techdev.trackr.domain.employee.expenses.reports.Report;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.List;
@RepositoryRestResource(path = "travelExpenseReportComments")
public interface CommentRepository extends CrudRepository<Comment, Long> {
@Override
@RestResource(exported = false)
Iterable<Comment> findAll();
@Override
@RestResource(exported = false)
Comment findOne(Long aLong);
@Override
@RestResource(exported = false)
void delete(Long aLong);
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username")
List<Comment> findByTravelExpenseReportOrderBySubmissionDateAsc(@Param("report") Report travelExpenseReport);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentWithEmployeeProjection.java
================================================
package de.techdev.trackr.domain.employee.expenses.reports.comments;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.rest.core.config.Projection;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Projection(types = Comment.class, name = "withEmployee")
public interface CommentWithEmployeeProjection {
Long getId();
String getText();
Date getSubmissionDate();
Employee getEmployee();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/login/PrincipalController.java
================================================
package de.techdev.trackr.domain.employee.login;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import de.techdev.trackr.domain.employee.Settings;
import de.techdev.trackr.domain.employee.SettingsRepository;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.Principal;
import java.util.Collection;
@Controller
@Slf4j
public class PrincipalController {
@Getter
@Setter
static class ReturnValue {
Collection<? extends GrantedAuthority> authorities;
String locale;
Long id;
String email;
}
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private SettingsRepository settingsRepository;
@RequestMapping(value = "/principal", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ReturnValue principal(Principal principal) {
if (principal != null) {
Employee employee = employeeRepository.findByEmail(principal.getName());
if (employee != null) {
Settings localeSettings = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, employee.getEmail());
ReturnValue value = new ReturnValue();
value.locale = localeSettings.getValue();
value.id = employee.getId();
value.authorities = ((Authentication) principal).getAuthorities();
value.email = principal.getName();
return value;
} else {
log.error("Somehow someone with an invalid email is in our system: {}", principal.getName());
throw new IllegalStateException("Invalid email address in principal.");
}
} else {
return null;
}
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/login/support/SupervisorService.java
================================================
package de.techdev.trackr.domain.employee.login.support;
import de.techdev.trackr.core.security.AuthorityService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
import java.util.function.Predicate;
public class SupervisorService {
@Autowired
private AuthorityService authorityService;
/**
* @return Email addresses of all supervisors
*/
public String[] getSupervisorEmailsAsArray() {
return getSupervisorEmailsArrayWithout(c -> true);
}
/**
* @param withoutThese A predicate to filter out supervisors, e.g. the logged in principal.
* @return Email addresses of all supervisors for whose credentials the predicate returns true.
*/
public String[] getSupervisorEmailsArrayWithout(Predicate<String> withoutThese) {
Collection<String> supervisor = authorityService.getEmployeeEmailsByAuthority("ROLE_SUPERVISOR");
return supervisor.stream().filter(withoutThese).toArray(String[]::new);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDays.java
================================================
package de.techdev.trackr.domain.employee.sickdays;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.validation.constraints.EndAfterBegin;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
@EndAfterBegin(begin = "startDate", end = "endDate")
public class SickDays {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@ManyToOne
@NotNull
private Employee employee;
@Temporal(TemporalType.DATE)
@NotNull
private Date startDate;
@Temporal(TemporalType.DATE)
private Date endDate;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysEventHandler.java
================================================
package de.techdev.trackr.domain.employee.sickdays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
@RepositoryEventHandler(value = SickDays.class)
@SuppressWarnings("unused")
public class SickDaysEventHandler {
@Autowired
private SickDaysNotifyService sickDaysNotifyService;
@HandleBeforeCreate
@PreAuthorize("#sickDays.employee.email == principal?.username or hasRole('ROLE_ADMIN')")
public void checkSaveAuthority(SickDays sickDays) {
sickDaysNotifyService.notifySupervisorsAboutNew(sickDays);
}
@HandleBeforeSave
@PreAuthorize("#sickDays.employee.email == principal?.username or hasRole('ROLE_ADMIN')")
public void checkUpdateAuthority(SickDays sickDays) {
sickDaysNotifyService.notifySupervisorsAboutUpdate(sickDays);
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkDeleteAuthority(SickDays sickDays) {
}
@HandleBeforeLinkSave
@PreAuthorize("denyAll()")
public void checkLinkUpdateAuthority(SickDays sickDays, Object links) {
//deny all
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void checkLinkSaveAuthority(SickDays sickDays, Object linkedEntity) {
//deny all
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysNotifyService.java
================================================
package de.techdev.trackr.domain.employee.sickdays;
import de.techdev.trackr.core.mail.MailService;
import de.techdev.trackr.domain.employee.login.support.SupervisorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import java.text.SimpleDateFormat;
/**
* @author Moritz Schulze
*/
public class SickDaysNotifyService {
@Autowired
private MailService mailService;
@Autowired
private SupervisorService supervisorService;
public void notifySupervisorsAboutNew(SickDays sickDays) {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
String subject = "Sick days reported by " + sickDays.getEmployee().fullName();
String text = sickDays.getEmployee().fullName() + " reported sick days from " + sdf.format(sickDays.getStartDate())
+ " to " + (sickDays.getEndDate() != null ? sdf.format(sickDays.getEndDate()) : " (not set)" ) + ".";
notifySupervisors(subject, text);
}
public void notifySupervisorsAboutUpdate(SickDays sickDays) {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
String subject = "Sick days updated by " + sickDays.getEmployee().fullName();
String text = sickDays.getEmployee().fullName() + " updated his sick days. Interval is now from " + sdf.format(sickDays.getStartDate())
+ " to " + (sickDays.getEndDate() != null ? sdf.format(sickDays.getEndDate()) : " (not set)") + ".";
notifySupervisors(subject, text);
}
protected void notifySupervisors(String subject, String text) {
String[] receiver = supervisorService.getSupervisorEmailsAsArray();
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject(subject);
mailMessage.setTo(receiver);
mailMessage.setText(text);
mailMessage.setFrom("no-reply@techdev.de");
mailService.sendMail(mailMessage);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysRepository.java
================================================
package de.techdev.trackr.domain.employee.sickdays;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
import java.util.List;
@RepositoryRestResource(path = "sickDays")
public interface SickDaysRepository extends JpaRepository<SickDays, Long> {
@Override
@RestResource(exported = false)
Page<SickDays> findAll(Pageable pageable);
@Override
@PostAuthorize("hasRole('ROLE_ADMIN') or principal?.username == returnObject.employee.email")
SickDays findOne(Long aLong);
@PreAuthorize("#employee.email == principal?.username")
List<SickDays> findByEmployee(@Param("employee") Employee employee);
@PreAuthorize("hasRole('ROLE_ADMIN')")
List<SickDays> findByStartDateBetweenOrEndDateBetween(
@Param("startLower") Date startLower,
@Param("startHigher") Date startHigher,
@Param("endLower") Date endLower,
@Param("endHigher") Date endHigher
);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysWithEmployeeProjection.java
================================================
package de.techdev.trackr.domain.employee.sickdays;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.rest.core.config.Projection;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Projection(types = SickDays.class, name = "withEmployee")
public interface SickDaysWithEmployeeProjection {
Long getId();
Integer getVersion();
Employee getEmployee();
Date getStartDate();
Date getEndDate();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/Holiday.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.common.FederalState;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
public class Holiday {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Temporal(TemporalType.DATE)
private Date day;
private String name;
@Enumerated(EnumType.STRING)
private FederalState federalState;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculator.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.common.FederalState;
import de.techdev.trackr.util.LocalDateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import static java.util.stream.Collectors.toList;
/**
* @author Moritz Schulze
*/
public class HolidayCalculator {
@Autowired
private HolidayRepository holidayRepository;
public Integer calculateDifferenceBetweenExcludingHolidaysAndWeekends(Date start, Date end, FederalState federalState) {
List<Holiday> holidays = holidayRepository.findByFederalStateAndDayBetween(federalState, start, end);
return calculateDifferenceBetweenExcludingHolidaysAndWeekends(LocalDateUtil.fromDate(start), LocalDateUtil.fromDate(end), holidays.stream()
.map(holiday -> LocalDateUtil.fromDate(holiday.getDay()))
.collect(toList()));
}
protected Integer calculateDifferenceBetweenExcludingHolidaysAndWeekends(LocalDate start, LocalDate end, List<LocalDate> holidays) {
LocalDate step = start;
Integer count = 0;
while(step.isBefore(end.plusDays(1))) {
if(!isWeekendOrHoliday(step, holidays)) {
count++;
}
step = step.plusDays(1);
}
return count;
}
/**
* Checks whether a date is a weekend day or in a given list of holidays.
*
* @param date The date to check
* @param holidays A list of dates that are seens as holidays
* @return True if the date is a sunday or saturday or in the list.
*/
protected boolean isWeekendOrHoliday(LocalDate date, List<LocalDate> holidays) {
return date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY || holidays.stream().anyMatch(date::equals);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayRepository.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.common.FederalState;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import java.util.Date;
import java.util.List;
/**
* @author Moritz Schulze
*/
public interface HolidayRepository extends CrudRepository<Holiday, Long> {
@Override
@RestResource(exported = false)
<S extends Holiday> S save(S entity);
@Override
@RestResource(exported = false)
void delete(Long id);
List<Holiday> findByFederalStateAndDayBetween(@Param("state") FederalState federalState, @Param("start") Date start, @Param("end") Date end);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequest.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import com.fasterxml.jackson.annotation.JsonIgnore;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.validation.constraints.EndAfterBegin;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
@EndAfterBegin(begin = "startDate", end = "endDate")
public class VacationRequest {
public enum VacationRequestStatus {
APPROVED, PENDING, REJECTED
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@ManyToOne
@NotNull
private Employee employee;
@Temporal(TemporalType.DATE)
@NotNull
private Date startDate;
@Temporal(TemporalType.DATE)
@NotNull
private Date endDate;
private Integer numberOfDays;
@Enumerated(EnumType.STRING)
private VacationRequestStatus status;
@Temporal(TemporalType.TIMESTAMP)
private Date approvalDate;
@Temporal(TemporalType.TIMESTAMP)
private Date submissionTime;
@ManyToOne
private Employee approver;
@JsonIgnore
public boolean isApproved() {
return status == VacationRequestStatus.APPROVED;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestApproveService.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.common.UuidMapper;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;
import de.techdev.trackr.util.LocalDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
@Slf4j
public class VacationRequestApproveService {
@Autowired
private VacationRequestRepository vacationRequestRepository;
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private VacationRequestNotifyService vacationRequestNotifyService;
@Autowired
private UuidMapper uuidMapper;
@Transactional
@PreAuthorize("hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email")
public VacationRequest approve(VacationRequest vacationRequest, String supervisorEmail) {
return setStatusOnVacationRequest(vacationRequest, supervisorEmail, VacationRequest.VacationRequestStatus.APPROVED);
}
/**
* Rejects a vacation request. The vacation request will be fetched from the repository, the rejector by the name given in
* supervisor email.
* <p>
* Will only reject pending vacation requests.
*
* @param vacationRequest The vacation request to reject.
* @param supervisorEmail The email address of the employee to use as the approver.
* @return The approved (or not) vacation request.
*/
@Transactional
@PreAuthorize("hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email")
public VacationRequest reject(VacationRequest vacationRequest, String supervisorEmail) {
return setStatusOnVacationRequest(vacationRequest, supervisorEmail, VacationRequest.VacationRequestStatus.REJECTED);
}
/**
* Approves all requests that are more than seven days old.
*/
@Transactional
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void approveSevenDayOldRequests() {
LocalDate oneWeekAgo = LocalDate.now().minusDays(7);
List<VacationRequest> vacationRequests = vacationRequestRepository.findBySubmissionTimeBeforeAndStatus(LocalDateUtil.fromLocalDate(oneWeekAgo), VacationRequest.VacationRequestStatus.PENDING);
vacationRequests.forEach(vacationRequest -> {
log.info("Approving more then seven days old vacation request {}", vacationRequest);
approve(vacationRequest, null);
});
}
protected VacationRequest setStatusOnVacationRequest(VacationRequest vacationRequest, String supervisorEmail, VacationRequest.VacationRequestStatus status) {
if (vacationRequest.getStatus() == VacationRequest.VacationRequestStatus.PENDING) {
Employee supervisor = null;
Employee byEmail = employeeRepository.findByEmail(supervisorEmail);
if (byEmail != null) {
supervisor = byEmail;
}
vacationRequest.setStatus(status);
vacationRequest.setApprover(supervisor);
vacationRequest.setApprovalDate(new Date());
vacationRequest = vacationRequestRepository.save(vacationRequest);
vacationRequestNotifyService.sendEmailNotification(vacationRequest);
}
uuidMapper.deleteUUID(vacationRequest.getId());
return vacationRequest;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestController.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.employee.vacation.support.VacationRequestEmployeeToDaysTotalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
import java.util.Date;
import java.util.Map;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping("/vacationRequests")
@Slf4j
public class VacationRequestController {
@Autowired
private VacationRequestApproveService vacationRequestApproveService;
@Autowired
private VacationRequestEmployeeToDaysTotalService vacationRequestEmployeeToDaysTotalService;
/**
* Approve a vacation request. Can only be done by supervisors, but they are not allowed to approve their own requests.
* Only works on pending requests.
*
* @param vacationRequest The vacation request to approve
* @param principal The Spring Security principal to extract the user from.
* @return The vacation request object.
*/
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
@RequestMapping(value = "/{id}/approve", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public VacationRequest approve(@PathVariable("id") VacationRequest vacationRequest, Principal principal) {
return vacationRequestApproveService.approve(vacationRequest, principal.getName());
}
/**
* Reject a vacation request. Can only be done by supervisors, but they are not allowed to reject their own requests.
* Only works on pending requests.
*
* @param vacationRequest The vacation request to reject.
* @param principal The Spring Security principal to extract the user from.
* @return The vacation request object.
*/
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
@RequestMapping(value = "/{id}/reject", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public VacationRequest reject(@PathVariable("id") VacationRequest vacationRequest, Principal principal) {
return vacationRequestApproveService.reject(vacationRequest, principal.getName());
}
/**
* Create a mapping of employee names to the effective number of vacation days between a start and end date.
*
* All approved vacation requests that coincide with the period are collected. Only the cut of every vacation request with the period is used for the calculation.
* Public holidays and weekends are excluded.
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@ResponseBody
@RequestMapping(value = "/daysPerEmployeeBetween", method = RequestMethod.GET, produces = "application/hal+json")
@ResponseStatus(HttpStatus.OK)
public Map<String, Integer> daysPerEmployeeBetween(
@RequestParam("start") Date start,
@RequestParam("end") Date end
) {
return vacationRequestEmployeeToDaysTotalService.mapVacationRequestsToTotalDays(start, end);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestEventHandler.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.common.UuidMapper;
import de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
import java.util.UUID;
@RepositoryEventHandler(VacationRequest.class)
@SuppressWarnings("unused")
public class VacationRequestEventHandler {
@Autowired
private HolidayCalculator holidayCalculator;
@Autowired
private VacationRequestNotifyService vacationRequestNotifyService;
@Autowired
private UuidMapper uuidMapper;
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN') or principal?.username == #vacationRequest.employee.email")
public void prepareVacationRequest(VacationRequest vacationRequest) {
Integer difference = holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(vacationRequest.getStartDate(),
vacationRequest.getEndDate(),
vacationRequest.getEmployee().getFederalState());
vacationRequest.setNumberOfDays(difference);
vacationRequest.setStatus(VacationRequest.VacationRequestStatus.PENDING);
vacationRequest.setApprover(null);
vacationRequest.setApprovalDate(null);
vacationRequest.setSubmissionTime(new Date());
}
@HandleAfterCreate
public void afterCreation(VacationRequest vacationRequest) {
UUID uuid = uuidMapper.createUUID(vacationRequest.getId());
vacationRequestNotifyService.notifySupervisors(vacationRequest, uuid);
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email")
public void authorizeUpdate(VacationRequest vacationRequest) {
}
@HandleBeforeDelete
@PreAuthorize("( hasRole('ROLE_SUPERVISOR') and @vacationRequestEventHandler.supervisorCanDeleteRequest(principal?.username, #vacationRequest) ) " +
"or @vacationRequestEventHandler.employeeCanDeleteRequest(principal?.username, #vacationRequest)")
public void authorizeDelete(VacationRequest vacationRequest) {
}
@HandleBeforeLinkSave
@PreAuthorize("denyAll()")
public void denyLinksSave(VacationRequest vacationRequest, Object links) {
//deny all, cannot be called
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void denyLinks(VacationRequest vacationRequest, Object linkedEntity) {
//deny all, cannot be called
}
/**
* Test if an employee may delete a vacation request. This means it is his own request and it is pending.
* @param username The email of the logged in user
* @param request The vacation request
* @return true if the user may delete, false otherwise.
*/
public boolean employeeCanDeleteRequest(String username, VacationRequest request) {
return username != null &&
username.equals(request.getEmployee().getEmail()) && request.getStatus() == VacationRequest.VacationRequestStatus.PENDING;
}
public boolean supervisorCanDeleteRequest(String username, VacationRequest request) {
return username != null &&
!username.equals(request.getEmployee().getEmail());
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepository.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
import java.util.List;
public interface VacationRequestRepository extends CrudRepository<VacationRequest, Long> {
@Override
@PostAuthorize("hasRole('ROLE_SUPERVISOR') or principal?.username == returnObject.employee.email")
VacationRequest findOne(Long aLong);
@Override
@RestResource(exported = false)
Iterable<VacationRequest> findAll();
@PreAuthorize("hasRole('ROLE_SUPERVISOR') or principal?.username == #employee.email")
List<VacationRequest> findByEmployeeOrderByStartDateAsc(@Param("employee") Employee employee);
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
List<VacationRequest> findByStatusOrderBySubmissionTimeAsc(@Param("status") VacationRequest.VacationRequestStatus status);
@RestResource(exported = false)
List<VacationRequest> findBySubmissionTimeBeforeAndStatus(Date date, VacationRequest.VacationRequestStatus status);
/**
* Find vacation requests of a certain status that overlap with a period.
*/
@RestResource(exported = false)
@Query("SELECT vr FROM VacationRequest vr WHERE (vr.startDate BETWEEN :startLower AND :startHigher OR vr.endDate BETWEEN :endLower AND :endHigher) AND vr.status = :status")
List<VacationRequest> findByStartDateBetweenOrEndDateBetweenAndStatus(
@Param("startLower") Date startLower, @Param("startHigher") Date startHigher,
@Param("endLower") Date endLower, @Param("endHigher") Date endHigher,
@Param("status") VacationRequest.VacationRequestStatus status);
/**
* Find one by id without security.
* @param id The id of the vacation request to find.
*/
@RestResource(exported = false)
@Query("SELECT vr FROM VacationRequest vr WHERE vr.id = :id")
VacationRequest findOneWithoutSecurity(@Param("id") Long id);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobs.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
/**
* @author Moritz Schulze
*/
@Slf4j
public class VacationRequestScheduledJobs {
@Autowired
private VacationRequestApproveService vacationRequestApproveService;
@Scheduled(cron = "0 0 4 * * *")
public void approveSevenDaysOldVacationRequests() {
log.debug("Executing vacation request approval trigger.");
vacationRequestApproveService.approveSevenDayOldRequests();
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestWithEmployeeAndApproverProjection.java
================================================
package de.techdev.trackr.domain.employee.vacation;
import de.techdev.trackr.domain.employee.Employee;
import org.springframework.data.rest.core.config.Projection;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Projection(types = VacationRequest.class, name = "withEmployeeAndApprover")
public interface VacationRequestWithEmployeeAndApproverProjection {
Long getId();
Employee getEmployee();
Date getStartDate();
Date getEndDate();
Integer getNumberOfDays();
VacationRequest.VacationRequestStatus getStatus();
Date getApprovalDate();
Date getSubmissionTime();
Employee getApprover();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveService.java
================================================
package de.techdev.trackr.domain.employee.vacation.support;
import de.techdev.trackr.domain.common.UuidMapper;
import de.techdev.trackr.domain.employee.vacation.VacationRequest;
import de.techdev.trackr.domain.employee.vacation.VacationRequestApproveService;
import de.techdev.trackr.domain.employee.vacation.VacationRequestRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.mail.Message;
import javax.mail.MessagingException;
import java.io.IOException;
@Slf4j
@Service
@Profile("gmail")
public class MailApproveService {
@Autowired
private UuidMapper uuidMapper;
@Autowired
private VacationRequestRepository vacationRequestRepository;
@Autowired
private VacationRequestApproveService vacationRequestApproveService;
public void approveOrRejectFromMail(Message mail) {
log.debug("Got mail.");
String subject;
String content;
String from;
MessageWrapper message = new MessageWrapper(mail);
try {
subject = mail.getSubject();
content = message.extractContentAsString();
from = message.getSender();
} catch (MessagingException | IOException e) {
throw new RuntimeException("Could not extract uuid or content from the mail.", e);
}
String uuid = uuidMapper.extractUUIDFromString(subject);
if (uuid == null) {
throw new RuntimeException("Could find a UUID in the subject " + subject);
}
log.debug("Extracted UUID {} from subject." , uuid);
Long id = uuidMapper.getIdFromUUID(uuid);
if (id != null) {
log.debug("Got ID {} from the mapper.", id);
actualApprove(id, from, content);
} else {
log.debug("Did not find an ID for UUID {}, deleting record.", uuid);
uuidMapper.deleteUUID(uuid);
}
}
/**
* Analyze the text of a mail and decide if the vacation request should be approved or rejected.
* If the word "approve" appears more often approve, if the word "reject" appears more often reject. If
* they appear with the same number, throw an {@link java.lang.IllegalArgumentException}.
* @param mailContent The content of the mail.
* @return The status APPROVED when to approve and the status REJECTED when to reject.
*/
protected VacationRequest.VacationRequestStatus approveOrReject(String mailContent) {
String mailContentLowerCase = mailContent.toLowerCase();
int approveCount = StringUtils.countOccurrencesOf(mailContentLowerCase, "approve");
int rejectCount = StringUtils.countOccurrencesOf(mailContentLowerCase, "reject");
if (approveCount > rejectCount) {
return VacationRequest.VacationRequestStatus.APPROVED;
} else if (approveCount < rejectCount) {
return VacationRequest.VacationRequestStatus.REJECTED;
} else {
throw new IllegalStateException("Cannot decide from the text if to approve or reject");
}
}
protected void actualApprove(Long vacationRequestId, String supervisorEmail, String content) {
VacationRequest vacationRequest = vacationRequestRepository.findOneWithoutSecurity(vacationRequestId);
if (vacationRequest == null) {
log.debug("Did not find a vacation request for id {}.", vacationRequestId);
return;
}
if (vacationRequest.getEmployee().getEmail().equals(supervisorEmail)) {
log.warn("Supervisor {} tried to approve his/her own vacation request via mail.", supervisorEmail);
return;
}
VacationRequest.VacationRequestStatus status = approveOrReject(content);
if (status == VacationRequest.VacationRequestStatus.APPROVED) {
vacationRequestApproveService.approve(vacationRequest, supervisorEmail);
} else if (status == VacationRequest.VacationRequestStatus.REJECTED) {
vacationRequestApproveService.reject(vacationRequest, supervisorEmail);
}
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapper.java
================================================
package de.techdev.trackr.domain.employee.vacation.support;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMultipart;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
class MessageWrapper {
private final Message message;
public MessageWrapper(Message message) {
this.message = message;
}
/**
* Extract the content of a Mail as a String depending on the content type.
* text/plain -> directly
* multipart/mime -> only the text/plain part if it exists, null otherwise
* multipart -> the body
* @return
* @throws IOException
* @throws MessagingException
*/
String extractContentAsString() throws IOException, MessagingException {
Object content = message.getContent();
if (content instanceof String) {
return (String) content;
}
if(content instanceof MimeMultipart) {
MimeMultipart multipart = (MimeMultipart) content;
for (int i = 0; i < multipart.getCount(); i++) {
if (multipart.getBodyPart(i).getContentType().startsWith("text/plain")) {
return (String)multipart.getBodyPart(i).getContent();
}
}
return null;
}
if (content instanceof Multipart) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
((Multipart) content).writeTo(outputStream);
return new String(outputStream.toByteArray(), "UTF-8");
}
throw new IllegalArgumentException("Incompatible message type.");
}
/**
* Extracts the sender of an email if it is an InternetAddress.
* @return The address or null if it's not a techdev address.
* @throws MessagingException
*/
String getSender() throws MessagingException {
String from = null;
Address[] fromArray = message.getFrom();
if (fromArray.length > 0) {
Address address = message.getFrom()[0];
if (address instanceof InternetAddress) {
from = ((InternetAddress) address).getAddress();
if (!from.endsWith("techdev.de")) {
from = null;
}
}
}
return from;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalService.java
================================================
package de.techdev.trackr.domain.employee.vacation.support;
import de.techdev.trackr.domain.employee.vacation.HolidayCalculator;
import de.techdev.trackr.domain.employee.vacation.VacationRequest;
import de.techdev.trackr.domain.employee.vacation.VacationRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
/**
* @author Moritz Schulze
*/
public class VacationRequestEmployeeToDaysTotalService {
@Autowired
private HolidayCalculator holidayCalculator;
@Autowired
private VacationRequestRepository vacationRequestRepository;
/**
* Groups vacation requests by their employee (the full name to be precise) and sums up all _actual_ vacation days between start and
* end for all vacation requests of that employee.
* @param start The start of the period
* @param end The end of the period
* @return A map of employee names to days of vacation in between start and end.
*/
public Map<String, Integer> mapVacationRequestsToTotalDays(Date start, Date end) {
List<VacationRequest> vacationRequests = vacationRequestRepository
.findByStartDateBetweenOrEndDateBetweenAndStatus(start, end, start, end, VacationRequest.VacationRequestStatus.APPROVED);
return mapToEmployeesAndSumUp(vacationRequests, vacationRequest -> getVacationDaysBetween(vacationRequest, start, end));
}
/**
* Groups vacation requests by employee names and adds for every vacation request the numbers returned by the mapper.
* @param vacationRequests The vacation requests to group
* @param numberExtractor A function that maps a vacation request to a number.
* @return A map of the employee names to the sum of numbers returned by the mapper for their vacation requests.
*/
protected Map<String, Integer> mapToEmployeesAndSumUp(List<VacationRequest> vacationRequests, ToIntFunction<VacationRequest> numberExtractor) {
return vacationRequests.stream().collect(
Collectors.groupingBy(
vacationRequest -> vacationRequest.getEmployee().getFirstName() + " " + vacationRequest.getEmployee().getLastName(),
Collectors.summingInt(numberExtractor)
)
);
}
/**
* @return Returns the number of days of the vacation request between start and end that aren't holidays or weekends.
*/
protected Integer getVacationDaysBetween(VacationRequest vacationRequest, Date start, Date end) {
return holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(
// If the start of the vacation request is before the desired period we use the period start
getMaximum(start, vacationRequest.getStartDate()),
// If the end of the vacation request is after the desired period we use the period end
getMinimum(end, vacationRequest.getEndDate()),
vacationRequest.getEmployee().getFederalState()
);
}
/**
* The minimum of the two dates. No null checks.
*/
protected Date getMinimum(Date a, Date b) {
return a.before(b) ? a : b;
}
/**
* The maximum of the two dates. No null checks.
*/
protected Date getMaximum(Date a, Date b) {
return a.before(b) ? b : a;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyService.java
================================================
package de.techdev.trackr.domain.employee.vacation.support;
import de.techdev.trackr.core.mail.MailService;
import de.techdev.trackr.domain.employee.login.support.SupervisorService;
import de.techdev.trackr.domain.employee.vacation.VacationRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import java.text.SimpleDateFormat;
import java.util.UUID;
public class VacationRequestNotifyService {
@Autowired
private MailService mailService;
@Autowired
private SupervisorService supervisorService;
/**
* Sends an approval or rejection mail depending on the status of the parameter.
* @param request The request for which the mail is to sent.
*/
public void sendEmailNotification(VacationRequest request) {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setFrom("no-reply@techdev.de");
mailMessage.setTo(request.getEmployee().getEmail());
mailMessage.setSubject("Your vacation request has been " + statusPastVerb(request.getStatus()));
mailMessage.setText(getStatusMailText(request));
mailService.sendMail(mailMessage);
}
protected String statusPastVerb(VacationRequest.VacationRequestStatus status) {
if(status == VacationRequest.VacationRequestStatus.APPROVED) {
return "approved";
} else if (status == VacationRequest.VacationRequestStatus.REJECTED) {
return "rejected";
} else {
return "is pending";
}
}
protected String getStatusMailText(VacationRequest request) {
if(request.getApprover() == null) {
return "Your vacation request has been automatically approved.";
} else {
return request.getApprover().fullName() + " has " + statusPastVerb(request.getStatus()) + " your vacation request from " + request.getSubmissionTime();
}
}
/**
* Send a new vacation request notification to all supervisors.
*/
public void notifySupervisors(VacationRequest vacationRequest, UUID uuid) {
SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
String[] receiver = supervisorService.getSupervisorEmailsAsArray();
SimpleMailMessage mailMessage = new SimpleMailMessage();
String subject = "New vacation request from " + vacationRequest.getEmployee().fullName() + "; " + uuid.toString();
String text = "New vacation request from " + vacationRequest.getEmployee().fullName() + " for " + sdf.format(vacationRequest.getStartDate()) + " - " + sdf
.format(vacationRequest.getEndDate()) + ". You can reply to this email with approve or reject to do that.";
mailMessage.setSubject(subject);
mailMessage.setTo(receiver);
mailMessage.setText(text);
mailMessage.setFrom("no-reply@techdev.de");
mailService.sendMail(mailMessage);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderService.java
================================================
package de.techdev.trackr.domain.employee.worktimetracking;
import de.techdev.trackr.core.mail.MailService;
import de.techdev.trackr.domain.common.FederalState;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.employee.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import java.util.List;
/**
* Remind employees to track their working times.
*/
public class WorkTimeTrackingReminderService {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private MailService mailService;
@Value("${trackr.frontendUrl}")
private String frontendUrl;
/**
* Remind all employees of a federal state to track their working times via mail. Since holidays differ in different states this needs the state.
* @param state The federal state to select employees from.
*/
public void remindEmployeesToTrackWorkTimes(FederalState state) {
List<Employee> allEmployees = employeeRepository.findByFederalState(state);
allEmployees.forEach(employee -> {
SimpleMailMessage mailMessage = getReminderMailMessage(employee);
mailService.sendMail(mailMessage);
});
}
protected SimpleMailMessage getReminderMailMessage(Employee employee) {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo(employee.getEmail());
mailMessage.setFrom("no-reply@techdev.de");
mailMessage.setSubject("Track your working time");
mailMessage.setText("Please make sure to track your working time by the end of the month: " + frontendUrl + "/employee/timesheet");
return mailMessage;
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/Project.java
================================================
package de.techdev.trackr.domain.project;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import de.techdev.trackr.domain.company.Company;
import de.techdev.trackr.domain.project.billtimes.BillableTime;
import de.techdev.trackr.domain.project.worktimes.WorkTime;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.Min;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
@JsonIgnoreProperties({"workTimes", "billableTimes"})
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotEmpty
@Column(unique = true)
private String identifier;
@NotEmpty
private String name;
@ManyToOne
@JoinColumn(name = "company_id")
private Company company;
@Min(0)
private Integer volume;
@Min(0)
private BigDecimal hourlyRate;
@Min(0)
private BigDecimal dailyRate;
@Min(0)
private BigDecimal fixedPrice;
@ManyToOne
@JoinColumn(name = "debitor_id")
private Company debitor;
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "project")
private List<WorkTime> workTimes = new ArrayList<>();
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "project")
private List<BillableTime> billableTimes = new ArrayList<>();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectEventHandler.java
================================================
package de.techdev.trackr.domain.project;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* @author Moritz Schulze
*/
@RepositoryEventHandler(Project.class)
@SuppressWarnings("unused")
public class ProjectEventHandler {
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkUpdatePermission(Project project) {
}
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkCreatePermission(Project project) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkDeletePermission(Project project) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkCompanyPermission(Project project, Object link) {
}
@HandleBeforeLinkDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void checkLinkDeletePermission(Project project, Object linkedEntity) {
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectRepository.java
================================================
package de.techdev.trackr.domain.project;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @author Moritz Schulze
*/
public interface ProjectRepository extends JpaRepository<Project, Long> {
Project findByIdentifier(@Param("identifier") String identifier);
List<Project> findByNameLikeIgnoreCaseOrIdentifierLikeIgnoreCaseOrderByNameAsc(@Param("name") String name, @Param("identifier") String identifier);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectWithCompanyAndDebitorProjection.java
================================================
package de.techdev.trackr.domain.project;
import de.techdev.trackr.domain.company.Company;
import org.springframework.data.rest.core.config.Projection;
import java.math.BigDecimal;
/**
* @author Moritz Schulze
*/
@Projection(types = Project.class, name = "withCompanyAndDebitor")
public interface ProjectWithCompanyAndDebitorProjection {
Long getId();
Integer getVersion();
String getIdentifier();
String getName();
Company getCompany();
Integer getVolume();
BigDecimal getHourlyRate();
BigDecimal getDailyRate();
BigDecimal getFixedPrice();
Company getDebitor();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTime.java
================================================
package de.techdev.trackr.domain.project.billtimes;
import de.techdev.trackr.domain.employee.Employee;
import de.techdev.trackr.domain.project.Project;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Entity
@Getter
@Setter
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"employee", "project", "date"}))
public class BillableTime {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@ManyToOne
@NotNull
@JoinColumn(name = "employee")
private Employee employee;
@ManyToOne
@NotNull
@JoinColumn(name = "project")
private Project project;
@NotNull
@Temporal(TemporalType.DATE)
private Date date;
@NotNull
@Min(0)
private Integer minutes;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeController.java
================================================
package de.techdev.trackr.domain.project.billtimes;
import de.techdev.trackr.domain.project.Project;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping("/billableTimes")
public class BillableTimeController {
@Autowired
@Qualifier("defaultConversionService")
private ConversionService conversionService;
@Autowired
private BillableTimeRepository billableTimeRepository;
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
@ResponseBody
@RequestMapping(value = "/findEmployeeMappingByProjectAndDateBetween", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Integer> findEmployeeMappingByProjectAndDateBetween(@RequestParam("project") String projectId,
@RequestParam("start") Date start,
@RequestParam("end") Date end) {
Project project = conversionService.convert(Long.valueOf(projectId), Project.class);
List<BillableTime> billableTimes = billableTimeRepository.findByProjectAndDateBetweenOrderByDateAsc(project, start, end);
return billableTimes.stream().collect(groupingBy(bt -> bt.getEmployee().fullName(), summingInt(BillableTime::getMinutes)));
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeEventHandler.java
================================================
package de.techdev.trackr.domain.project.billtimes;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* @author Moritz Schulze
*/
@RepositoryEventHandler(BillableTime.class)
@SuppressWarnings("unused")
public class BillableTimeEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkCreateAuthority(BillableTime billableTime) {
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkUpdateAuthority(BillableTime billableTime) {
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkDeleteAuthority(BillableTime billableTime) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
public void checkLinkSaveAuthority(BillableTime billableTime, Object links) {
}
@HandleBeforeLinkDelete
@PreAuthorize("denyAll()")
public void checkLinkDeleteAuthority(BillableTime billableTime, Object linkedEntity) {
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeRepository.java
================================================
package de.techdev.trackr.domain.project.billtimes;
import de.techdev.trackr.domain.project.Project;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Date;
import java.util.List;
/**
* @author Moritz Schulze
*/
public interface BillableTimeRepository extends CrudRepository<BillableTime, Long> {
@Override
@RestResource(exported = false)
Iterable<BillableTime> findAll();
@Override
@RestResource(exported = false)
Iterable<BillableTime> findAll(Iterable<Long> longs);
@Override
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
BillableTime findOne(Long aLong);
@PreAuthorize("hasRole('ROLE_SUPERVISOR')")
List<BillableTime> findByProjectAndDateBetweenOrderByDateAsc(@Param("project") Project project,
@Param("start") Date start,
@Param("end") Date end);
@PreAuthorize("hasRole('ROLE_ADMIN')")
List<BillableTime> findByDateBetween(@Param("start") Date start, @Param("end") Date end);
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeWithProjectProjection.java
================================================
package de.techdev.trackr.domain.project.billtimes;
import de.techdev.trackr.domain.project.Project;
import org.springframework.data.rest.core.config.Projection;
import java.util.Date;
/**
* @author Moritz Schulze
*/
@Projection(types = BillableTime.class, name = "withProject")
public interface BillableTimeWithProjectProjection {
Long getId();
Integer getVersion();
Project getProject();
Date getDate();
Integer getMinutes();
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/ChangeStateService.java
================================================
package de.techdev.trackr.domain.project.invoice;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Moritz Schulze
*/
public class ChangeStateService {
@Autowired
private InvoiceRepository invoiceRepository;
public Invoice changeState(Invoice invoice, Invoice.InvoiceState invoiceState) {
invoice.setInvoiceState(invoiceState);
return invoiceRepository.save(invoice);
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/Invoice.java
================================================
package de.techdev.trackr.domain.project.invoice;
import de.techdev.trackr.domain.company.Company;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.*;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
@Entity
@Getter
@Setter
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "identifier"))
public class Invoice {
public enum InvoiceState {
OUTSTANDING, PAID, OVERDUE
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Integer version;
@NotEmpty
private String identifier;
@NotNull
@Temporal(TemporalType.DATE)
private Date creationDate;
@Min(0)
private BigDecimal invoiceTotal;
@ManyToOne
@JoinColumn(name = "debitor")
private Company debitor;
@Temporal(TemporalType.DATE)
private Date dueDate;
@NotNull
@Enumerated(EnumType.STRING)
private InvoiceState invoiceState;
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceController.java
================================================
package de.techdev.trackr.domain.project.invoice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Moritz Schulze
*/
@Controller
@RequestMapping(value = "/invoices")
public class InvoiceController {
@Autowired
private ChangeStateService changeStateService;
@Autowired
private InvoiceRepository invoiceRepository;
@RequestMapping(value = "{id}/markPaid", method = RequestMethod.POST)
@ResponseBody
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String markAsPaid(@PathVariable("id") Long invoiceId) {
Invoice invoice = invoiceRepository.findOne(invoiceId);
changeStateService.changeState(invoice, Invoice.InvoiceState.PAID);
return "Ok.";
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandler.java
================================================
package de.techdev.trackr.domain.project.invoice;
import de.techdev.trackr.domain.company.Company;
import de.techdev.trackr.util.LocalDateUtil;
import org.springframework.data.rest.core.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import java.time.LocalDate;
import static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;
/**
* @author Moritz Schulze
*/
@RepositoryEventHandler(Invoice.class)
@SuppressWarnings("unused")
public class InvoiceEventHandler {
@HandleBeforeCreate
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void authorizeCreate(Invoice invoice) {
setDueDateFromTimeForPayment(invoice);
setInvoiceStateIfNecessary(invoice);
}
@HandleBeforeSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void authorizeUpdate(Invoice invoice) {
setDueDateFromTimeForPayment(invoice);
setInvoiceStateIfNecessary(invoice);
}
@HandleBeforeDelete
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void authorizeDelete(Invoice invoice) {
}
@HandleBeforeLinkSave
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void linkSave(Invoice invoice, Object links) {
if (links instanceof Company) {
setDueDateFromTimeForPayment(invoice);
setInvoiceStateIfNecessary(invoice);
}
}
/**
* Sets the invoice state to OVERDUE if the due date is before today.
*/
protected void setInvoiceStateIfNecessary(Invoice invoice) {
if (invoice.getDueDate() != null) {
LocalDate today = LocalDate.now();
if (invoice.getDueDate().before(fromLocalDate(today))) {
invoice.setInvoiceState(Invoice.InvoiceState.OVERDUE);
} else {
invoice.setInvoiceState(Invoice.InvoiceState.OUTSTANDING);
}
}
}
/**
* Set the due date automatically if it is not set and the debitor of the invoice has a timeForPayment.
*/
protected void setDueDateFromTimeForPayment(Invoice invoice) {
if (invoice.getDueDate() == null && invoice.getDebitor() != null && invoice.getDebitor().getTimeForPayment() != null) {
LocalDate creationDate = LocalDateUtil.fromDate(invoice.getCreationDate());
LocalDate dueDate = creationDate.plusDays(invoice.getDebitor().getTimeForPayment());
invoice.setDueDate(LocalDateUtil.fromLocalDate(dueDate));
}
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceOverdueService.java
================================================
package de.techdev.trackr.domain.project.invoice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.List;
import static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;
/**
* Marks invoices as overdue if the due date is after today.
* @author Moritz Schulze
*/
@Slf4j
public class InvoiceOverdueService {
@Autowired
private InvoiceRepository invoiceRepository;
/**
* Mark all outstanding invoices with a due date after expiry date as overdue.
* @param expiryDate The date to use as a bound.
*/
@Transactional
public void markOverdueInvoices(LocalDate expiryDate) {
List<Invoice> invoices = invoiceRepository.findByDueDateBeforeAndInvoiceState(fromLocalDate(expiryDate), Invoice.InvoiceState.OUTSTANDING);
for (Invoice invoice : invoices) {
log.info("Setting state to overdue on invoice {}", invoice);
invoice.setInvoiceState(Invoice.InvoiceState.OVERDUE);
invoiceRepository.save(invoice);
}
}
}
================================================
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceRepository.java
================================================
package de.techdev.trackr.domain.project.invoice;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
imp
gitextract_0tzlhsw6/
├── .gitignore
├── LICENSE
├── README.md
├── application.yaml
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src/
├── main/
│ ├── java/
│ │ └── de/
│ │ └── techdev/
│ │ └── trackr/
│ │ ├── Trackr.java
│ │ ├── core/
│ │ │ ├── mail/
│ │ │ │ ├── GMailConfiguration.java
│ │ │ │ ├── MailService.java
│ │ │ │ └── support/
│ │ │ │ ├── AsyncMailService.java
│ │ │ │ └── NoOpJavaMailSender.java
│ │ │ ├── pdf/
│ │ │ │ ├── HtmlPdfConverter.java
│ │ │ │ ├── PdfCreationException.java
│ │ │ │ ├── PdfRenderer.java
│ │ │ │ └── ThymeleafRenderer.java
│ │ │ ├── security/
│ │ │ │ ├── AuthorityService.java
│ │ │ │ ├── InMemoryAuthorityService.java
│ │ │ │ ├── InMemorySecurityConfiguration.java
│ │ │ │ ├── MethodSecurityConfiguration.java
│ │ │ │ ├── OAuth2AuthorityService.java
│ │ │ │ └── OAuth2ResourceServerConfiguration.java
│ │ │ └── web/
│ │ │ ├── api/
│ │ │ │ ├── ApiRepositoryRestConfiguration.java
│ │ │ │ ├── ApiWebMvcConfiguration.java
│ │ │ │ ├── ArgumentResolverPagingAndSortingTemplateVariables.java
│ │ │ │ ├── ExceptionHandlers.java
│ │ │ │ ├── JsonMappingHandlerExceptionResolver.java
│ │ │ │ └── RepositoryEntityLinksWithoutProjection.java
│ │ │ └── converters/
│ │ │ └── DateConverter.java
│ │ ├── domain/
│ │ │ ├── ApiBeansConfiguration.java
│ │ │ ├── common/
│ │ │ │ ├── EmployeeSettingsLocaleResolver.java
│ │ │ │ ├── FederalState.java
│ │ │ │ ├── FederalStateController.java
│ │ │ │ └── UuidMapper.java
│ │ │ ├── company/
│ │ │ │ ├── Address.java
│ │ │ │ ├── AddressEventHandler.java
│ │ │ │ ├── AddressRepository.java
│ │ │ │ ├── Company.java
│ │ │ │ ├── CompanyEventHandler.java
│ │ │ │ ├── CompanyRepository.java
│ │ │ │ ├── CompanyWithAddressAndContactPersonsProjection.java
│ │ │ │ ├── ContactPerson.java
│ │ │ │ ├── ContactPersonEventHandler.java
│ │ │ │ └── ContactPersonRepository.java
│ │ │ ├── employee/
│ │ │ │ ├── Employee.java
│ │ │ │ ├── EmployeeController.java
│ │ │ │ ├── EmployeeEventHandler.java
│ │ │ │ ├── EmployeeRepository.java
│ │ │ │ ├── EmployeeScheduledJob.java
│ │ │ │ ├── Projections.java
│ │ │ │ ├── SelfEmployee.java
│ │ │ │ ├── SelfEmployeeRepository.java
│ │ │ │ ├── Settings.java
│ │ │ │ ├── SettingsRepository.java
│ │ │ │ ├── addressbook/
│ │ │ │ │ ├── AddressBookController.java
│ │ │ │ │ └── EmployeeForAddressBookDTO.java
│ │ │ │ ├── expenses/
│ │ │ │ │ ├── TravelExpense.java
│ │ │ │ │ ├── TravelExpenseEventHandler.java
│ │ │ │ │ ├── TravelExpenseRepository.java
│ │ │ │ │ ├── TravelExpenseTypeController.java
│ │ │ │ │ └── reports/
│ │ │ │ │ ├── Projections.java
│ │ │ │ │ ├── Report.java
│ │ │ │ │ ├── ReportController.java
│ │ │ │ │ ├── ReportEventHandler.java
│ │ │ │ │ ├── ReportNotifyService.java
│ │ │ │ │ ├── ReportRepository.java
│ │ │ │ │ ├── ReportService.java
│ │ │ │ │ └── comments/
│ │ │ │ │ ├── Comment.java
│ │ │ │ │ ├── CommentEventHandler.java
│ │ │ │ │ ├── CommentRepository.java
│ │ │ │ │ └── CommentWithEmployeeProjection.java
│ │ │ │ ├── login/
│ │ │ │ │ ├── PrincipalController.java
│ │ │ │ │ └── support/
│ │ │ │ │ └── SupervisorService.java
│ │ │ │ ├── sickdays/
│ │ │ │ │ ├── SickDays.java
│ │ │ │ │ ├── SickDaysEventHandler.java
│ │ │ │ │ ├── SickDaysNotifyService.java
│ │ │ │ │ ├── SickDaysRepository.java
│ │ │ │ │ └── SickDaysWithEmployeeProjection.java
│ │ │ │ ├── vacation/
│ │ │ │ │ ├── Holiday.java
│ │ │ │ │ ├── HolidayCalculator.java
│ │ │ │ │ ├── HolidayRepository.java
│ │ │ │ │ ├── VacationRequest.java
│ │ │ │ │ ├── VacationRequestApproveService.java
│ │ │ │ │ ├── VacationRequestController.java
│ │ │ │ │ ├── VacationRequestEventHandler.java
│ │ │ │ │ ├── VacationRequestRepository.java
│ │ │ │ │ ├── VacationRequestScheduledJobs.java
│ │ │ │ │ ├── VacationRequestWithEmployeeAndApproverProjection.java
│ │ │ │ │ └── support/
│ │ │ │ │ ├── MailApproveService.java
│ │ │ │ │ ├── MessageWrapper.java
│ │ │ │ │ ├── VacationRequestEmployeeToDaysTotalService.java
│ │ │ │ │ └── VacationRequestNotifyService.java
│ │ │ │ └── worktimetracking/
│ │ │ │ └── WorkTimeTrackingReminderService.java
│ │ │ ├── project/
│ │ │ │ ├── Project.java
│ │ │ │ ├── ProjectEventHandler.java
│ │ │ │ ├── ProjectRepository.java
│ │ │ │ ├── ProjectWithCompanyAndDebitorProjection.java
│ │ │ │ ├── billtimes/
│ │ │ │ │ ├── BillableTime.java
│ │ │ │ │ ├── BillableTimeController.java
│ │ │ │ │ ├── BillableTimeEventHandler.java
│ │ │ │ │ ├── BillableTimeRepository.java
│ │ │ │ │ └── BillableTimeWithProjectProjection.java
│ │ │ │ ├── invoice/
│ │ │ │ │ ├── ChangeStateService.java
│ │ │ │ │ ├── Invoice.java
│ │ │ │ │ ├── InvoiceController.java
│ │ │ │ │ ├── InvoiceEventHandler.java
│ │ │ │ │ ├── InvoiceOverdueService.java
│ │ │ │ │ ├── InvoiceRepository.java
│ │ │ │ │ ├── InvoiceScheduledJob.java
│ │ │ │ │ └── InvoiceWithDebitorProjection.java
│ │ │ │ └── worktimes/
│ │ │ │ ├── CustomWorkTime.java
│ │ │ │ ├── Projections.java
│ │ │ │ ├── WorkTime.java
│ │ │ │ ├── WorkTimeController.java
│ │ │ │ ├── WorkTimeEmployee.java
│ │ │ │ ├── WorkTimeEventHandler.java
│ │ │ │ └── WorkTimeRepository.java
│ │ │ ├── scheduling/
│ │ │ │ ├── LastWorkdayDayOfMonthTrigger.java
│ │ │ │ └── ScheduledJobsConfiguration.java
│ │ │ ├── translations/
│ │ │ │ └── TranslationController.java
│ │ │ └── validation/
│ │ │ ├── EndAfterBeginValidator.java
│ │ │ ├── ProjectBelongsToCompanyValidator.java
│ │ │ └── constraints/
│ │ │ ├── EndAfterBegin.java
│ │ │ └── ProjectBelongsToCompany.java
│ │ └── util/
│ │ └── LocalDateUtil.java
│ └── resources/
│ ├── META-INF/
│ │ └── mail-integration.xml
│ ├── banner.txt
│ ├── data.sql
│ ├── db/
│ │ └── migration/
│ │ ├── V10__modify_travel_expense_add_comment.sql
│ │ ├── V11__add_travel_expense_report_comments.sql
│ │ ├── V12__modify_company_add_time_for_payment.sql
│ │ ├── V13__modify_travel_expense_reports_add_debitor_and_project.sql
│ │ ├── V14__add_uuid_mapping.sql
│ │ ├── V15__migrate_credentials.sql
│ │ ├── V16__add_holidays_2015.sql
│ │ ├── V17__add_holidays_2015.sql
│ │ ├── V18__expense_paid_marker.sql
│ │ ├── V19__add_employee_address.sql
│ │ ├── V1__create_schema.sql
│ │ ├── V20__add_employe_deleted.sql
│ │ ├── V2__add_roles.sql
│ │ ├── V3__add_holidays_2014.sql
│ │ ├── V4__add_invoices.sql
│ │ ├── V5__modify_vacationrequests.sql
│ │ ├── V6__modify_travel_expense_reports_and_contact_persons.sql
│ │ ├── V7__update_travel_expense_report_submission_date_from_travel_expenses.sql
│ │ ├── V8__add_sick_days.sql
│ │ └── V9__modify_travel_expense_report.sql
│ ├── i18n/
│ │ ├── trackr-de.json
│ │ ├── trackr-en.json
│ │ └── validation/
│ │ ├── messages_de.properties
│ │ └── messages_en.properties
│ ├── logback-console.xml
│ ├── logback-file.xml
│ └── pdfTemplates/
│ └── travel-expenses/
│ └── report.html
└── test/
├── java/
│ └── de/
│ └── techdev/
│ ├── test/
│ │ ├── FlywayTest.java
│ │ ├── InMemoryOAuth2ResourceServerConfiguration.java
│ │ ├── TestConstants.java
│ │ ├── TransactionalIntegrationTest.java
│ │ ├── oauth/
│ │ │ ├── OAuthRequest.java
│ │ │ └── OAuthTestExecutionListener.java
│ │ └── rest/
│ │ ├── AbstractDomainResourceSecurityTest.java
│ │ ├── AbstractJsonGenerator.java
│ │ ├── AbstractRestIntegrationTest.java
│ │ ├── DomainResourceTestMatchers.java
│ │ └── TestRestTemplate.java
│ └── trackr/
│ ├── core/
│ │ └── web/
│ │ └── converters/
│ │ └── DateConverterTest.java
│ └── domain/
│ ├── common/
│ │ ├── FederalStateControllerIntegrationTest.java
│ │ ├── UuidMapperIntegrationTest.java
│ │ └── UuidMapperTest.java
│ ├── company/
│ │ ├── AddressJsonGenerator.java
│ │ ├── AddressResourceSecurityTest.java
│ │ ├── CompanyJsonGenerator.java
│ │ ├── CompanyRepositoryTest.java
│ │ ├── CompanyResourceSecurityTest.java
│ │ ├── ContactPersonJsonGenerator.java
│ │ └── ContactPersonResourceSecurityTest.java
│ ├── employee/
│ │ ├── EmployeeControllerSecurityTest.java
│ │ ├── EmployeeJsonGenerator.java
│ │ ├── EmployeeResourceIntegrationTest.java
│ │ ├── EmployeeResourceSecurityTest.java
│ │ ├── SelfEmployeeRepositoryTest.java
│ │ ├── addressbook/
│ │ │ ├── AddressBookControllerSecurityTest.java
│ │ │ └── AddressBookControllerTest.java
│ │ ├── expenses/
│ │ │ ├── TravelExpenseJsonGenerator.java
│ │ │ ├── TravelExpenseResourceSecurityTest.java
│ │ │ └── report/
│ │ │ ├── ReportJsonGenerator.java
│ │ │ ├── ReportResourceSecurityTest.java
│ │ │ ├── ReportServiceTest.java
│ │ │ └── comment/
│ │ │ ├── CommentJsonGenerator.java
│ │ │ └── CommentResourceSecurityTest.java
│ │ ├── login/
│ │ │ └── PrincipalControllerSecurityTest.java
│ │ ├── sickdays/
│ │ │ ├── SickDaysJsonGenerator.java
│ │ │ └── SickDaysResourceSecurityTest.java
│ │ ├── vacation/
│ │ │ ├── HolidayCalculatorTest.java
│ │ │ ├── HolidayResourceTest.java
│ │ │ ├── VacationRequestControllerSecurityTest.java
│ │ │ ├── VacationRequestJsonGenerator.java
│ │ │ ├── VacationRequestRepositoryTest.java
│ │ │ ├── VacationRequestResourceSecurityTest.java
│ │ │ ├── VacationRequestScheduledJobsTest.java
│ │ │ └── support/
│ │ │ ├── MailApproveServiceTest.java
│ │ │ ├── MessageWrapperTest.java
│ │ │ ├── VacationRequestEmployeeToDaysTotalServiceTest.java
│ │ │ └── VacationRequestNotifyServiceTest.java
│ │ └── worktimetracking/
│ │ └── WorkTimeTrackingReminderServiceIntegrationTest.java
│ ├── project/
│ │ ├── ProjectJsonGenerator.java
│ │ ├── ProjectResourceSecurityTest.java
│ │ ├── billtimes/
│ │ │ ├── BillableTimeControllerIntegrationTest.java
│ │ │ ├── BillableTimeResourceSecurityTest.java
│ │ │ └── BillableTimesJsonGenerator.java
│ │ ├── invoice/
│ │ │ ├── InvoiceEventHandlerTest.java
│ │ │ ├── InvoiceJsonGenerator.java
│ │ │ └── InvoiceResourceSecurityTest.java
│ │ └── worktimes/
│ │ ├── CustomWorkTimeTest.java
│ │ ├── WorkTimeControllerSecurityTest.java
│ │ ├── WorkTimeControllerTest.java
│ │ ├── WorkTimeJsonGenerator.java
│ │ ├── WorkTimeRepositoryTest.java
│ │ └── WorkTimeResourceSecurityTest.java
│ ├── scheduling/
│ │ └── LastWorkdayDayOfMonthTriggerTest.java
│ └── translations/
│ ├── TranslationControllerSecurityTest.java
│ └── TranslationControllerTest.java
└── resources/
└── de/
└── techdev/
└── trackr/
└── domain/
├── company/
│ ├── address/
│ │ └── resourceTest.sql
│ ├── contactPerson/
│ │ └── resourceTest.sql
│ ├── repositoryTest.sql
│ └── resourceTest.sql
├── employee/
│ ├── expenses/
│ │ ├── report/
│ │ │ ├── comment/
│ │ │ │ └── resourceTest.sql
│ │ │ └── resourceTest.sql
│ │ └── resourceTest.sql
│ ├── login/
│ │ └── resourceTest.sql
│ ├── resourceTest.sql
│ ├── sickdays/
│ │ └── resourceTest.sql
│ └── vacation/
│ ├── holiday/
│ │ └── resourceTest.sql
│ ├── repositoryTest.sql
│ └── resourceTest.sql
├── emptyDatabase.sql
├── project/
│ ├── billtimes/
│ │ └── resourceTest.sql
│ ├── invoice/
│ │ └── resourceTest.sql
│ ├── resourceTest.sql
│ └── worktimes/
│ ├── repositoryTest.sql
│ └── resourceTest.sql
└── tableUuidMapping.sql
SYMBOL INDEX (1087 symbols across 191 files)
FILE: src/main/java/de/techdev/trackr/Trackr.java
class Trackr (line 18) | @SpringBootApplication(exclude = MailSenderAutoConfiguration.class)
method primaryDataSource (line 22) | @Bean
method handlePid (line 29) | @PostConstruct
method main (line 36) | public static void main(String[] args) {
FILE: src/main/java/de/techdev/trackr/core/mail/GMailConfiguration.java
class GMailConfiguration (line 21) | @Configuration
method mailSender (line 29) | @Bean
method applyProperties (line 36) | private void applyProperties(JavaMailSenderImpl sender) {
method asProperties (line 52) | private Properties asProperties(Map<String, String> source) {
method mailSession (line 61) | @Bean
FILE: src/main/java/de/techdev/trackr/core/mail/MailService.java
type MailService (line 8) | public interface MailService {
method sendMail (line 10) | void sendMail(SimpleMailMessage mailMessage);
FILE: src/main/java/de/techdev/trackr/core/mail/support/AsyncMailService.java
class AsyncMailService (line 16) | @Component
method sendMail (line 23) | @Override
FILE: src/main/java/de/techdev/trackr/core/mail/support/NoOpJavaMailSender.java
class NoOpJavaMailSender (line 14) | @Slf4j
method createMimeMessage (line 19) | @Override
method createMimeMessage (line 25) | @Override
method send (line 31) | @Override
method send (line 36) | @Override
method send (line 41) | @Override
method send (line 46) | @Override
method send (line 51) | @Override
method send (line 64) | @Override
FILE: src/main/java/de/techdev/trackr/core/pdf/HtmlPdfConverter.java
class HtmlPdfConverter (line 12) | public class HtmlPdfConverter {
method HtmlPdfConverter (line 16) | public HtmlPdfConverter() {
method renderHtmlToPdf (line 25) | public byte[] renderHtmlToPdf(String htmlContent) throws PdfCreationEx...
FILE: src/main/java/de/techdev/trackr/core/pdf/PdfCreationException.java
class PdfCreationException (line 6) | public class PdfCreationException extends Exception {
method PdfCreationException (line 7) | public PdfCreationException(Exception e) {
FILE: src/main/java/de/techdev/trackr/core/pdf/PdfRenderer.java
class PdfRenderer (line 12) | @Slf4j
method PdfRenderer (line 26) | public PdfRenderer() {
method setUpRenderer (line 30) | @PostConstruct
method renderPdf (line 35) | public byte[] renderPdf(String templateName, Context context) throws P...
FILE: src/main/java/de/techdev/trackr/core/pdf/ThymeleafRenderer.java
class ThymeleafRenderer (line 13) | @Slf4j
method ThymeleafRenderer (line 22) | public ThymeleafRenderer(String templatePath, String templateSuffix) {
method setUpTemplateEngine (line 28) | private void setUpTemplateEngine() {
method renderTemplateToHtml (line 47) | public String renderTemplateToHtml(String templateName, Context contex...
FILE: src/main/java/de/techdev/trackr/core/security/AuthorityService.java
type AuthorityService (line 8) | public interface AuthorityService {
method getEmployeeEmailsByAuthority (line 13) | Collection<String> getEmployeeEmailsByAuthority(String authority);
FILE: src/main/java/de/techdev/trackr/core/security/InMemoryAuthorityService.java
class InMemoryAuthorityService (line 13) | @Service
method getEmployeeEmailsByAuthority (line 20) | @Override
FILE: src/main/java/de/techdev/trackr/core/security/InMemorySecurityConfiguration.java
class InMemorySecurityConfiguration (line 24) | @EnableWebSecurity
method configure (line 32) | @Override
method configure (line 45) | @Override
FILE: src/main/java/de/techdev/trackr/core/security/MethodSecurityConfiguration.java
class MethodSecurityConfiguration (line 21) | @Profile("granular-security")
method createExpressionHandler (line 32) | @Override
method roleHierarchy (line 42) | @Bean
method roleVoter (line 49) | @Bean
FILE: src/main/java/de/techdev/trackr/core/security/OAuth2AuthorityService.java
class OAuth2AuthorityService (line 12) | @Service
method OAuth2AuthorityService (line 18) | @Autowired
method getEmployeeEmailsByAuthority (line 23) | @Override
FILE: src/main/java/de/techdev/trackr/core/security/OAuth2ResourceServerConfiguration.java
class OAuth2ResourceServerConfiguration (line 24) | @Profile("oauth")
method oauthDataSource (line 32) | @Bean
method tokenStore (line 39) | @Bean
method configure (line 45) | @Override
method configure (line 50) | @Override
FILE: src/main/java/de/techdev/trackr/core/web/api/ApiRepositoryRestConfiguration.java
class ApiRepositoryRestConfiguration (line 27) | @Configuration
method configureRepositoryRestConfiguration (line 30) | @Override
method configureConversionService (line 39) | @Override
method dateConverter (line 45) | @Bean
method configureValidatingRepositoryEventListener (line 53) | @Override
method validator (line 62) | @Bean
method messageSource (line 72) | @Bean
FILE: src/main/java/de/techdev/trackr/core/web/api/ApiWebMvcConfiguration.java
class ApiWebMvcConfiguration (line 16) | @Configuration
method entityLinks (line 26) | @Override
method localeResolver (line 33) | @Bean
method addFormatters (line 38) | @Override
method jsonMappingHandlerExceptionResolver (line 51) | @Bean
method extendHandlerExceptionResolvers (line 56) | @Override
FILE: src/main/java/de/techdev/trackr/core/web/api/ArgumentResolverPagingAndSortingTemplateVariables.java
class ArgumentResolverPagingAndSortingTemplateVariables (line 24) | @Deprecated
method ArgumentResolverPagingAndSortingTemplateVariables (line 30) | public ArgumentResolverPagingAndSortingTemplateVariables(HateoasPageab...
method getPaginationTemplateVariables (line 37) | public TemplateVariables getPaginationTemplateVariables(MethodParamete...
method getSortTemplateVariables (line 41) | public TemplateVariables getSortTemplateVariables(MethodParameter para...
method enhance (line 45) | public void enhance(UriComponentsBuilder builder, MethodParameter para...
method supportsParameter (line 54) | public boolean supportsParameter(MethodParameter parameter) {
FILE: src/main/java/de/techdev/trackr/core/web/api/ExceptionHandlers.java
class ExceptionHandlers (line 21) | @ControllerAdvice
method ExceptionHandlers (line 27) | @Autowired
method handleJpaSystemException (line 38) | @ExceptionHandler(JpaSystemException.class)
method handleRepositoryConstraintViolationException (line 50) | @ResponseBody
FILE: src/main/java/de/techdev/trackr/core/web/api/JsonMappingHandlerExceptionResolver.java
class JsonMappingHandlerExceptionResolver (line 27) | public class JsonMappingHandlerExceptionResolver implements HandlerExcep...
method JsonMappingHandlerExceptionResolver (line 31) | public JsonMappingHandlerExceptionResolver() {
method resolveException (line 35) | @Override
method writeExceptionAsJsonToOutput (line 66) | protected void writeExceptionAsJsonToOutput(InvalidFormatException ex,...
method getFieldPath (line 84) | private String getFieldPath(InvalidFormatException ex) {
FILE: src/main/java/de/techdev/trackr/core/web/api/RepositoryEntityLinksWithoutProjection.java
class RepositoryEntityLinksWithoutProjection (line 22) | @Deprecated
method RepositoryEntityLinksWithoutProjection (line 37) | public RepositoryEntityLinksWithoutProjection(Repositories repositorie...
method linkToSingleResource (line 43) | @Override
FILE: src/main/java/de/techdev/trackr/core/web/converters/DateConverter.java
class DateConverter (line 15) | public class DateConverter implements Converter<String, Date> {
method DateConverter (line 21) | public DateConverter() {
method convert (line 26) | @Override
FILE: src/main/java/de/techdev/trackr/domain/ApiBeansConfiguration.java
class ApiBeansConfiguration (line 25) | @Configuration
method travelExpenseReportService (line 31) | @Bean
method travelExpenseReportNotifyService (line 36) | @Bean
method workTimeTrackingReminderService (line 41) | @Bean
method vacationRequestNotifyService (line 46) | @Bean
method vacationRequestService (line 51) | @Bean
method vacationRequestEmployeeToDaysTotalService (line 56) | @Bean
method holidayCalculator (line 61) | @Bean
method invoiceOverdueService (line 66) | @Bean
method changeStateService (line 71) | @Bean
method sickDaysNotifyService (line 76) | @Bean
method supervisorService (line 81) | @Bean
method pdfRenderer (line 86) | @Bean
method uuidMapper (line 91) | @Bean
FILE: src/main/java/de/techdev/trackr/domain/common/EmployeeSettingsLocaleResolver.java
class EmployeeSettingsLocaleResolver (line 19) | public class EmployeeSettingsLocaleResolver implements LocaleContextReso...
method resolveLocale (line 24) | @Override
method setLocale (line 29) | @Override
method resolveLocaleContext (line 36) | @Override
method setLocaleContext (line 44) | @Override
method getLocaleFromSessionOrAuthentication (line 57) | protected Locale getLocaleFromSessionOrAuthentication(HttpServletReque...
FILE: src/main/java/de/techdev/trackr/domain/common/FederalState.java
type FederalState (line 8) | @JsonFormat(shape= JsonFormat.Shape.OBJECT)
method FederalState (line 17) | FederalState(String state) {
method getState (line 21) | public String getState() {
method getName (line 25) | public String getName() {
FILE: src/main/java/de/techdev/trackr/domain/common/FederalStateController.java
class FederalStateController (line 16) | @Controller
method federalStates (line 20) | @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLI...
FILE: src/main/java/de/techdev/trackr/domain/common/UuidMapper.java
class UuidMapper (line 17) | public class UuidMapper {
method extractUUIDFromString (line 24) | public String extractUUIDFromString(String input) {
method getIdFromUUID (line 33) | public Long getIdFromUUID(String uuid) {
method deleteUUID (line 48) | public void deleteUUID(String uuid) {
method deleteUUID (line 58) | public void deleteUUID(Long id) {
method createUUID (line 68) | public UUID createUUID(Long id) {
FILE: src/main/java/de/techdev/trackr/domain/company/Address.java
class Address (line 9) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/company/AddressEventHandler.java
class AddressEventHandler (line 17) | @RepositoryEventHandler(Address.class)
method checkSaveAuthority (line 21) | @HandleBeforeCreate
method checkUpdateAuthority (line 26) | @HandleBeforeSave
method checkDeleteAuthority (line 31) | @HandleBeforeDelete
FILE: src/main/java/de/techdev/trackr/domain/company/AddressRepository.java
type AddressRepository (line 14) | public interface AddressRepository extends JpaRepository<Address, Long> {
method findAll (line 16) | @Override
method findAll (line 20) | @Override
method findAll (line 24) | @Override
method delete (line 28) | @Override
method delete (line 32) | @Override
FILE: src/main/java/de/techdev/trackr/domain/company/Company.java
class Company (line 19) | @Getter
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyEventHandler.java
class CompanyEventHandler (line 11) | @RepositoryEventHandler(Company.class)
method checkSaveAuthority (line 15) | @HandleBeforeCreate
method checkUpdateAuthority (line 20) | @HandleBeforeSave
method checkDeleteAuthority (line 25) | @HandleBeforeDelete
method beforeAddContactPerson (line 30) | @HandleBeforeLinkSave
method beforeDeleteContactPerson (line 35) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyRepository.java
type CompanyRepository (line 12) | @RepositoryRestResource(path = "/companies")
method findByCompanyId (line 15) | Company findByCompanyId(@Param("companyId") Long companyId);
method findByNameLikeIgnoreCaseOrderByNameAsc (line 17) | List<Company> findByNameLikeIgnoreCaseOrderByNameAsc(@Param("name") St...
FILE: src/main/java/de/techdev/trackr/domain/company/CompanyWithAddressAndContactPersonsProjection.java
type CompanyWithAddressAndContactPersonsProjection (line 10) | @Projection(types = Company.class, name = "withAddressAndContactPersons")
method getId (line 13) | Long getId();
method getVersion (line 15) | Integer getVersion();
method getCompanyId (line 17) | Long getCompanyId();
method getName (line 19) | String getName();
method getTimeForPayment (line 21) | Integer getTimeForPayment();
method getAddress (line 23) | Address getAddress();
method getContactPersons (line 25) | List<ContactPerson> getContactPersons();
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPerson.java
class ContactPerson (line 14) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPersonEventHandler.java
class ContactPersonEventHandler (line 9) | @RepositoryEventHandler(ContactPerson.class)
method checkCreateAuthority (line 13) | @HandleBeforeCreate
method checkUpdateAuthority (line 18) | @HandleBeforeSave
method checkDeleteAuthority (line 23) | @HandleBeforeDelete
method checkLinkUpdateAuthority (line 28) | @HandleBeforeLinkSave
method checkLinkDeleteAuthority (line 34) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/company/ContactPersonRepository.java
type ContactPersonRepository (line 8) | public interface ContactPersonRepository extends CrudRepository<ContactP...
FILE: src/main/java/de/techdev/trackr/domain/employee/Employee.java
class Employee (line 26) | @Entity
method fullName (line 91) | public String fullName() {
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeController.java
class EmployeeController (line 15) | @Controller
method updateSelf (line 30) | @ResponseBody
method get (line 41) | @RequestMapping(value = "/{employee}/self", method = {RequestMethod.GET})
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeEventHandler.java
class EmployeeEventHandler (line 7) | @RepositoryEventHandler(Employee.class)
method checkCreateAuthority (line 14) | @HandleBeforeCreate
method createInitialSettings (line 19) | @HandleAfterCreate
method checkUpdateAuthority (line 28) | @HandleBeforeSave
method checkDeleteAuthority (line 33) | @HandleBeforeDelete
method deleteCredentialForbidden (line 38) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeRepository.java
type EmployeeRepository (line 16) | public interface EmployeeRepository extends JpaRepository<Employee, Long> {
method findOne (line 18) | @Override
method findAll (line 22) | @Override
method findAll (line 26) | @Override
method findAll (line 30) | @Override
method findAll (line 34) | @Override
method findByFederalState (line 38) | @RestResource(exported = false)
method findAllForAddressBook (line 46) | @RestResource(exported = false)
method findByEmail (line 50) | @RestResource(exported = false)
FILE: src/main/java/de/techdev/trackr/domain/employee/EmployeeScheduledJob.java
class EmployeeScheduledJob (line 9) | @Slf4j
method sendWorkTimeReminderTask (line 22) | public Runnable sendWorkTimeReminderTask(FederalState state) {
FILE: src/main/java/de/techdev/trackr/domain/employee/Projections.java
class Projections (line 10) | public class Projections {
type WithAddressProjection (line 12) | @Projection(types = Employee.class, name = "withAddress")
method getId (line 15) | Long getId();
method getVersion (line 17) | Integer getVersion();
method getFirstName (line 19) | String getFirstName();
method getLastName (line 21) | String getLastName();
method getEmail (line 23) | String getEmail();
method getPhoneNumber (line 25) | String getPhoneNumber();
method getTitle (line 27) | String getTitle();
method getSalary (line 29) | BigDecimal getSalary();
method getHourlyCostRate (line 31) | BigDecimal getHourlyCostRate();
method getJoinDate (line 33) | Date getJoinDate();
method getLeaveDate (line 35) | Date getLeaveDate();
method getFederalState (line 37) | FederalState getFederalState();
method getVacationEntitlement (line 39) | Float getVacationEntitlement();
method getAddress (line 41) | Address getAddress();
method isDeleted (line 43) | boolean isDeleted();
FILE: src/main/java/de/techdev/trackr/domain/employee/SelfEmployee.java
class SelfEmployee (line 11) | @Getter
method valueOf (line 34) | public static SelfEmployee valueOf(Employee employee) {
FILE: src/main/java/de/techdev/trackr/domain/employee/SelfEmployeeRepository.java
class SelfEmployeeRepository (line 10) | @Repository
method save (line 26) | @Transactional
method findOne (line 42) | public SelfEmployee findOne(Long employeeId) {
FILE: src/main/java/de/techdev/trackr/domain/employee/Settings.java
class Settings (line 10) | @Entity
type SettingsType (line 16) | public enum SettingsType {
FILE: src/main/java/de/techdev/trackr/domain/employee/SettingsRepository.java
type SettingsRepository (line 8) | @RepositoryRestResource(exported = false)
method save (line 11) | Settings save(Settings settings);
method findByEmployee_Email (line 13) | List<Settings> findByEmployee_Email(String email);
method findByTypeAndEmployee_Email (line 15) | Settings findByTypeAndEmployee_Email(Settings.SettingsType type, Strin...
FILE: src/main/java/de/techdev/trackr/domain/employee/addressbook/AddressBookController.java
class AddressBookController (line 23) | @Controller
method getAddressList (line 30) | @PreAuthorize("hasRole('ROLE_EMPLOYEE')")
method transformToReducedEmployees (line 47) | protected List<EmployeeForAddressBookDTO> transformToReducedEmployees(...
method pageMetadataFromPage (line 54) | protected PagedResources.PageMetadata pageMetadataFromPage(Page page) {
FILE: src/main/java/de/techdev/trackr/domain/employee/addressbook/EmployeeForAddressBookDTO.java
class EmployeeForAddressBookDTO (line 11) | @Getter
method valueOf (line 29) | static EmployeeForAddressBookDTO valueOf(Employee employee) {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpense.java
class TravelExpense (line 13) | @Getter
type Type (line 19) | public enum Type {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseEventHandler.java
class TravelExpenseEventHandler (line 7) | @RepositoryEventHandler(TravelExpense.class)
method checkCreateAuthority (line 11) | @HandleBeforeCreate
method checkUpdateAuthority (line 16) | @HandleBeforeSave
method checkDeleteAuthority (line 21) | @HandleBeforeDelete
method denyLinkSave (line 26) | @HandleBeforeLinkSave
method denyLinkDelete (line 32) | @HandleBeforeLinkDelete
method canCreate (line 38) | public boolean canCreate(String email, TravelExpense travelExpense) {
method canEdit (line 44) | public boolean canEdit(String email, TravelExpense travelExpense) {
method canDelete (line 50) | public boolean canDelete(String email, TravelExpense travelExpense) {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseRepository.java
type TravelExpenseRepository (line 10) | public interface TravelExpenseRepository extends CrudRepository<TravelEx...
method findAll (line 12) | @Override
method findOne (line 16) | @Override
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseTypeController.java
class TravelExpenseTypeController (line 16) | @Controller
method types (line 20) | @ResponseBody
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Projections.java
class Projections (line 15) | public class Projections {
type TravelExpenseReportForOverviewProjection (line 16) | @Projection(types = Report.class, name = "overview")
method getId (line 18) | Long getId();
method getEmployee (line 20) | Employee getEmployee();
method getStatus (line 22) | Report.Status getStatus();
method getExpenses (line 24) | List<TravelExpense> getExpenses();
method getSubmissionDate (line 26) | Date getSubmissionDate();
method getApprovalDate (line 28) | Date getApprovalDate();
method getApprover (line 30) | Employee getApprover();
method getDebitor (line 32) | Company getDebitor();
method getProject (line 34) | Project getProject();
type TravelExpenseReportWithEmployeeAndTravelExpensesProjection (line 37) | @Projection(types = Report.class, name = "withEmployeeAndExpenses")
method getId (line 39) | Long getId();
method getVersion (line 41) | Integer getVersion();
method getEmployee (line 43) | Employee getEmployee();
method getExpenses (line 45) | List<TravelExpense> getExpenses();
method getStatus (line 47) | Report.Status getStatus();
method getSubmissionDate (line 49) | Date getSubmissionDate();
type TravelExpenseReportWithExpensesAndDebitorProjection (line 52) | @Projection(types = Report.class, name = "withExpensesAndDebitor")
method getId (line 54) | Long getId();
method getVersion (line 56) | Integer getVersion();
method getExpenses (line 58) | List<TravelExpense> getExpenses();
method getStatus (line 60) | Report.Status getStatus();
method getSubmissionDate (line 62) | Date getSubmissionDate();
method getApprovalDate (line 64) | Date getApprovalDate();
method getDebitor (line 66) | Company getDebitor();
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Report.java
class Report (line 20) | @Getter
type Status (line 27) | public enum Status {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportController.java
class ReportController (line 22) | @Controller
method submit (line 35) | @RequestMapping(value = "/{id}/submit", method = RequestMethod.PUT)
method approve (line 42) | @RequestMapping(value = "/{id}/approve", method = RequestMethod.PUT)
method reject (line 49) | @RequestMapping(value = "/{id}/reject", method = RequestMethod.PUT)
method asPdf (line 56) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.empl...
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportEventHandler.java
class ReportEventHandler (line 8) | @RepositoryEventHandler(Report.class)
method checkCreateAuthority (line 12) | @HandleBeforeCreate
method checkUpdateAuthority (line 17) | @HandleBeforeSave
method checkDeleteAuthority (line 22) | @HandleBeforeDelete
method checkLinkSaveAuthority (line 27) | @HandleBeforeLinkSave
method checkLinkDeleteAuthority (line 38) | @HandleBeforeLinkDelete
method employeeCanDeleteReport (line 46) | public boolean employeeCanDeleteReport(Report report, String username) {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportNotifyService.java
class ReportNotifyService (line 15) | public class ReportNotifyService {
method notifySupervisorsOnSubmission (line 34) | public void notifySupervisorsOnSubmission(Report report) {
method getWebLink (line 50) | protected String getWebLink(Report report) {
method notifyEmployeeOnApproval (line 54) | public void notifyEmployeeOnApproval(Report report) {
method notifyEmployeeOnRejection (line 58) | public void notifyEmployeeOnRejection(Report report) {
method notifyEmployeeOnStatusChange (line 62) | private void notifyEmployeeOnStatusChange(Report report, String outcom...
method getTotalAmount (line 74) | @Transactional
method fullName (line 84) | protected String fullName(Employee employee) {
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportRepository.java
type ReportRepository (line 16) | @RepositoryRestResource(path = "travelExpenseReports")
method findAll (line 19) | @Override
method findOne (line 23) | @Override
method findByEmployeeAndStatusOrderByStatusAsc (line 27) | @PreAuthorize("#employee.email == principal?.username")
method findByStatus (line 30) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method findBySubmissionDateBetween (line 33) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportService.java
class ReportService (line 11) | @Transactional
method submit (line 23) | @PreAuthorize("#travelExpenseReport.employee.email == principal?.usern...
method accept (line 29) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.emp...
method reject (line 36) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.emp...
method setStatusOnTravelExpenseReport (line 43) | private Report setStatusOnTravelExpenseReport(Report travelExpenseRepo...
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/Comment.java
class Comment (line 16) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentEventHandler.java
class CommentEventHandler (line 8) | @RepositoryEventHandler(value = Comment.class)
method checkCreateAuthority (line 12) | @HandleBeforeCreate
method checkUpdateAuthority (line 18) | @HandleBeforeSave
method checkLinkSaveAuthority (line 24) | @HandleBeforeLinkSave
method checkLinkDeleteAuthority (line 30) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentRepository.java
type CommentRepository (line 12) | @RepositoryRestResource(path = "travelExpenseReportComments")
method findAll (line 15) | @Override
method findOne (line 19) | @Override
method delete (line 23) | @Override
method findByTravelExpenseReportOrderBySubmissionDateAsc (line 27) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.empl...
FILE: src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentWithEmployeeProjection.java
type CommentWithEmployeeProjection (line 11) | @Projection(types = Comment.class, name = "withEmployee")
method getId (line 13) | Long getId();
method getText (line 15) | String getText();
method getSubmissionDate (line 17) | Date getSubmissionDate();
method getEmployee (line 19) | Employee getEmployee();
FILE: src/main/java/de/techdev/trackr/domain/employee/login/PrincipalController.java
class PrincipalController (line 21) | @Controller
class ReturnValue (line 25) | @Getter
method principal (line 40) | @RequestMapping(value = "/principal", produces = MediaType.APPLICATION...
FILE: src/main/java/de/techdev/trackr/domain/employee/login/support/SupervisorService.java
class SupervisorService (line 9) | public class SupervisorService {
method getSupervisorEmailsAsArray (line 17) | public String[] getSupervisorEmailsAsArray() {
method getSupervisorEmailsArrayWithout (line 25) | public String[] getSupervisorEmailsArrayWithout(Predicate<String> with...
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDays.java
class SickDays (line 15) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysEventHandler.java
class SickDaysEventHandler (line 7) | @RepositoryEventHandler(value = SickDays.class)
method checkSaveAuthority (line 14) | @HandleBeforeCreate
method checkUpdateAuthority (line 20) | @HandleBeforeSave
method checkDeleteAuthority (line 26) | @HandleBeforeDelete
method checkLinkUpdateAuthority (line 31) | @HandleBeforeLinkSave
method checkLinkSaveAuthority (line 37) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysNotifyService.java
class SickDaysNotifyService (line 13) | public class SickDaysNotifyService {
method notifySupervisorsAboutNew (line 21) | public void notifySupervisorsAboutNew(SickDays sickDays) {
method notifySupervisorsAboutUpdate (line 29) | public void notifySupervisorsAboutUpdate(SickDays sickDays) {
method notifySupervisors (line 37) | protected void notifySupervisors(String subject, String text) {
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysRepository.java
type SickDaysRepository (line 16) | @RepositoryRestResource(path = "sickDays")
method findAll (line 19) | @Override
method findOne (line 23) | @Override
method findByEmployee (line 27) | @PreAuthorize("#employee.email == principal?.username")
method findByStartDateBetweenOrEndDateBetween (line 30) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysWithEmployeeProjection.java
type SickDaysWithEmployeeProjection (line 11) | @Projection(types = SickDays.class, name = "withEmployee")
method getId (line 13) | Long getId();
method getVersion (line 15) | Integer getVersion();
method getEmployee (line 17) | Employee getEmployee();
method getStartDate (line 19) | Date getStartDate();
method getEndDate (line 21) | Date getEndDate();
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/Holiday.java
class Holiday (line 13) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculator.java
class HolidayCalculator (line 17) | public class HolidayCalculator {
method calculateDifferenceBetweenExcludingHolidaysAndWeekends (line 22) | public Integer calculateDifferenceBetweenExcludingHolidaysAndWeekends(...
method calculateDifferenceBetweenExcludingHolidaysAndWeekends (line 29) | protected Integer calculateDifferenceBetweenExcludingHolidaysAndWeeken...
method isWeekendOrHoliday (line 48) | protected boolean isWeekendOrHoliday(LocalDate date, List<LocalDate> h...
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayRepository.java
type HolidayRepository (line 14) | public interface HolidayRepository extends CrudRepository<Holiday, Long> {
method save (line 16) | @Override
method delete (line 20) | @Override
method findByFederalStateAndDayBetween (line 24) | List<Holiday> findByFederalStateAndDayBetween(@Param("state") FederalS...
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequest.java
class VacationRequest (line 16) | @Entity
type VacationRequestStatus (line 22) | public enum VacationRequestStatus {
method isApproved (line 59) | @JsonIgnore
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestApproveService.java
class VacationRequestApproveService (line 17) | @Slf4j
method approve (line 32) | @Transactional
method reject (line 48) | @Transactional
method approveSevenDayOldRequests (line 57) | @Transactional
method setStatusOnVacationRequest (line 68) | protected VacationRequest setStatusOnVacationRequest(VacationRequest v...
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestController.java
class VacationRequestController (line 18) | @Controller
method approve (line 37) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method reject (line 53) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method daysPerEmployeeBetween (line 67) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestEventHandler.java
class VacationRequestEventHandler (line 12) | @RepositoryEventHandler(VacationRequest.class)
method prepareVacationRequest (line 25) | @HandleBeforeCreate
method afterCreation (line 38) | @HandleAfterCreate
method authorizeUpdate (line 44) | @HandleBeforeSave
method authorizeDelete (line 49) | @HandleBeforeDelete
method denyLinksSave (line 55) | @HandleBeforeLinkSave
method denyLinks (line 61) | @HandleBeforeLinkDelete
method employeeCanDeleteRequest (line 73) | public boolean employeeCanDeleteRequest(String username, VacationReque...
method supervisorCanDeleteRequest (line 78) | public boolean supervisorCanDeleteRequest(String username, VacationReq...
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepository.java
type VacationRequestRepository (line 14) | public interface VacationRequestRepository extends CrudRepository<Vacati...
method findOne (line 16) | @Override
method findAll (line 20) | @Override
method findByEmployeeOrderByStartDateAsc (line 24) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') or principal?.username == #e...
method findByStatusOrderBySubmissionTimeAsc (line 27) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method findBySubmissionTimeBeforeAndStatus (line 30) | @RestResource(exported = false)
method findByStartDateBetweenOrEndDateBetweenAndStatus (line 36) | @RestResource(exported = false)
method findOneWithoutSecurity (line 47) | @RestResource(exported = false)
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobs.java
class VacationRequestScheduledJobs (line 10) | @Slf4j
method approveSevenDaysOldVacationRequests (line 16) | @Scheduled(cron = "0 0 4 * * *")
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestWithEmployeeAndApproverProjection.java
type VacationRequestWithEmployeeAndApproverProjection (line 11) | @Projection(types = VacationRequest.class, name = "withEmployeeAndApprov...
method getId (line 13) | Long getId();
method getEmployee (line 15) | Employee getEmployee();
method getStartDate (line 17) | Date getStartDate();
method getEndDate (line 19) | Date getEndDate();
method getNumberOfDays (line 21) | Integer getNumberOfDays();
method getStatus (line 23) | VacationRequest.VacationRequestStatus getStatus();
method getApprovalDate (line 25) | Date getApprovalDate();
method getSubmissionTime (line 27) | Date getSubmissionTime();
method getApprover (line 29) | Employee getApprover();
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveService.java
class MailApproveService (line 17) | @Slf4j
method approveOrRejectFromMail (line 31) | public void approveOrRejectFromMail(Message mail) {
method approveOrReject (line 68) | protected VacationRequest.VacationRequestStatus approveOrReject(String...
method actualApprove (line 82) | protected void actualApprove(Long vacationRequestId, String supervisor...
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapper.java
class MessageWrapper (line 12) | class MessageWrapper {
method MessageWrapper (line 16) | public MessageWrapper(Message message) {
method extractContentAsString (line 29) | String extractContentAsString() throws IOException, MessagingException {
method getSender (line 56) | String getSender() throws MessagingException {
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalService.java
class VacationRequestEmployeeToDaysTotalService (line 17) | public class VacationRequestEmployeeToDaysTotalService {
method mapVacationRequestsToTotalDays (line 32) | public Map<String, Integer> mapVacationRequestsToTotalDays(Date start,...
method mapToEmployeesAndSumUp (line 44) | protected Map<String, Integer> mapToEmployeesAndSumUp(List<VacationReq...
method getVacationDaysBetween (line 56) | protected Integer getVacationDaysBetween(VacationRequest vacationReque...
method getMinimum (line 69) | protected Date getMinimum(Date a, Date b) {
method getMaximum (line 76) | protected Date getMaximum(Date a, Date b) {
FILE: src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyService.java
class VacationRequestNotifyService (line 12) | public class VacationRequestNotifyService {
method sendEmailNotification (line 24) | public void sendEmailNotification(VacationRequest request) {
method statusPastVerb (line 33) | protected String statusPastVerb(VacationRequest.VacationRequestStatus ...
method getStatusMailText (line 43) | protected String getStatusMailText(VacationRequest request) {
method notifySupervisors (line 54) | public void notifySupervisors(VacationRequest vacationRequest, UUID uu...
FILE: src/main/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderService.java
class WorkTimeTrackingReminderService (line 16) | public class WorkTimeTrackingReminderService {
method remindEmployeesToTrackWorkTimes (line 31) | public void remindEmployeesToTrackWorkTimes(FederalState state) {
method getReminderMailMessage (line 39) | protected SimpleMailMessage getReminderMailMessage(Employee employee) {
FILE: src/main/java/de/techdev/trackr/domain/project/Project.java
class Project (line 20) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectEventHandler.java
class ProjectEventHandler (line 9) | @RepositoryEventHandler(Project.class)
method checkUpdatePermission (line 13) | @HandleBeforeSave
method checkCreatePermission (line 18) | @HandleBeforeCreate
method checkDeletePermission (line 23) | @HandleBeforeDelete
method checkCompanyPermission (line 28) | @HandleBeforeLinkSave
method checkLinkDeletePermission (line 33) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectRepository.java
type ProjectRepository (line 11) | public interface ProjectRepository extends JpaRepository<Project, Long> {
method findByIdentifier (line 13) | Project findByIdentifier(@Param("identifier") String identifier);
method findByNameLikeIgnoreCaseOrIdentifierLikeIgnoreCaseOrderByNameAsc (line 15) | List<Project> findByNameLikeIgnoreCaseOrIdentifierLikeIgnoreCaseOrderB...
FILE: src/main/java/de/techdev/trackr/domain/project/ProjectWithCompanyAndDebitorProjection.java
type ProjectWithCompanyAndDebitorProjection (line 11) | @Projection(types = Project.class, name = "withCompanyAndDebitor")
method getId (line 13) | Long getId();
method getVersion (line 15) | Integer getVersion();
method getIdentifier (line 17) | String getIdentifier();
method getName (line 19) | String getName();
method getCompany (line 21) | Company getCompany();
method getVolume (line 23) | Integer getVolume();
method getHourlyRate (line 25) | BigDecimal getHourlyRate();
method getDailyRate (line 27) | BigDecimal getDailyRate();
method getFixedPrice (line 29) | BigDecimal getFixedPrice();
method getDebitor (line 31) | Company getDebitor();
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTime.java
class BillableTime (line 16) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeController.java
class BillableTimeController (line 25) | @Controller
method findEmployeeMappingByProjectAndDateBetween (line 36) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeEventHandler.java
class BillableTimeEventHandler (line 9) | @RepositoryEventHandler(BillableTime.class)
method checkCreateAuthority (line 13) | @HandleBeforeCreate
method checkUpdateAuthority (line 18) | @HandleBeforeSave
method checkDeleteAuthority (line 23) | @HandleBeforeDelete
method checkLinkSaveAuthority (line 28) | @HandleBeforeLinkSave
method checkLinkDeleteAuthority (line 33) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeRepository.java
type BillableTimeRepository (line 15) | public interface BillableTimeRepository extends CrudRepository<BillableT...
method findAll (line 16) | @Override
method findAll (line 20) | @Override
method findOne (line 24) | @Override
method findByProjectAndDateBetweenOrderByDateAsc (line 28) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method findByDateBetween (line 33) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeWithProjectProjection.java
type BillableTimeWithProjectProjection (line 11) | @Projection(types = BillableTime.class, name = "withProject")
method getId (line 13) | Long getId();
method getVersion (line 15) | Integer getVersion();
method getProject (line 17) | Project getProject();
method getDate (line 19) | Date getDate();
method getMinutes (line 21) | Integer getMinutes();
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/ChangeStateService.java
class ChangeStateService (line 8) | public class ChangeStateService {
method changeState (line 13) | public Invoice changeState(Invoice invoice, Invoice.InvoiceState invoi...
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/Invoice.java
class Invoice (line 14) | @Entity
type InvoiceState (line 20) | public enum InvoiceState {
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceController.java
class InvoiceController (line 14) | @Controller
method markAsPaid (line 24) | @RequestMapping(value = "{id}/markPaid", method = RequestMethod.POST)
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandler.java
class InvoiceEventHandler (line 15) | @RepositoryEventHandler(Invoice.class)
method authorizeCreate (line 19) | @HandleBeforeCreate
method authorizeUpdate (line 26) | @HandleBeforeSave
method authorizeDelete (line 33) | @HandleBeforeDelete
method linkSave (line 38) | @HandleBeforeLinkSave
method setInvoiceStateIfNecessary (line 50) | protected void setInvoiceStateIfNecessary(Invoice invoice) {
method setDueDateFromTimeForPayment (line 64) | protected void setDueDateFromTimeForPayment(Invoice invoice) {
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceOverdueService.java
class InvoiceOverdueService (line 16) | @Slf4j
method markOverdueInvoices (line 26) | @Transactional
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceRepository.java
type InvoiceRepository (line 17) | public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
method findOne (line 19) | @Override
method findAll (line 23) | @Override
method findByInvoiceState (line 27) | @PreAuthorize("hasRole('ROLE_ADMIN')")
method findByIdentifierLikeIgnoreCaseAndInvoiceState (line 30) | @PreAuthorize("hasRole('ROLE_ADMIN')")
method findByDueDateBeforeAndInvoiceState (line 33) | @RestResource(exported = false)
method findByCreationDateBetween (line 36) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceScheduledJob.java
class InvoiceScheduledJob (line 11) | public class InvoiceScheduledJob {
method markOverdueInvoices (line 16) | @Scheduled(cron = "0 0 1 * * *")
FILE: src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceWithDebitorProjection.java
type InvoiceWithDebitorProjection (line 12) | @Projection(types = Invoice.class, name = "withDebitor")
method getId (line 14) | Long getId();
method getVersion (line 16) | Integer getVersion();
method getIdentifier (line 18) | String getIdentifier();
method getCreationDate (line 20) | Date getCreationDate();
method getInvoiceTotal (line 22) | BigDecimal getInvoiceTotal();
method getDebitor (line 24) | Company getDebitor();
method getDueDate (line 26) | Date getDueDate();
method getInvoiceState (line 28) | Invoice.InvoiceState getInvoiceState();
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/CustomWorkTime.java
class CustomWorkTime (line 18) | @Getter
method reduceAndSortWorktimes (line 38) | public static List<CustomWorkTime> reduceAndSortWorktimes(List<CustomW...
method addOtherWorkTime (line 45) | private CustomWorkTime addOtherWorkTime(CustomWorkTime other) {
method addComment (line 54) | private void addComment(String comment) {
method valueOf (line 62) | public static CustomWorkTime valueOf(WorkTime workTime) {
method compareTo (line 70) | @Override
method equals (line 75) | @Override
method hashCode (line 90) | @Override
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/Projections.java
class Projections (line 13) | public class Projections {
type WorkTimeWithEmployeeProjection (line 14) | @Projection(types = WorkTime.class, name = "withEmployee")
method getId (line 16) | Long getId();
method getVersion (line 18) | Integer getVersion();
method getEmployee (line 20) | Employee getEmployee();
method getDate (line 22) | Date getDate();
method getStartTime (line 24) | Time getStartTime();
method getEndTime (line 26) | Time getEndTime();
method getComment (line 28) | String getComment();
type WorkTimeWithProjectProjection (line 31) | @Projection(types = WorkTime.class, name = "withProject")
method getId (line 33) | Long getId();
method getVersion (line 35) | Integer getVersion();
method getProject (line 37) | Project getProject();
method getDate (line 39) | Date getDate();
method getStartTime (line 41) | Time getStartTime();
method getEndTime (line 43) | Time getEndTime();
method getComment (line 45) | String getComment();
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTime.java
class WorkTime (line 17) | @Entity
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeController.java
class WorkTimeController (line 31) | @Controller
method findEmployeeMappingByProjectAndDateBetween (line 56) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method getBilledMinutesMapping (line 77) | protected Map<Long, Map<Date, BillableTime>> getBilledMinutesMapping(D...
method convertStreamOfWorkTimesToMap (line 93) | protected Map<Long, WorkTimeEmployee> convertStreamOfWorkTimesToMap(Li...
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEmployee.java
class WorkTimeEmployee (line 19) | @Getter
method valueOf (line 36) | public static WorkTimeEmployee valueOf(Employee employee, List<CustomW...
method addBilledMinutes (line 43) | public void addBilledMinutes(Map<Date, BillableTime> dateBillableTimeM...
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEventHandler.java
class WorkTimeEventHandler (line 8) | @RepositoryEventHandler(WorkTime.class)
method checkCreateAuthority (line 12) | @HandleBeforeCreate
method checkUpdateAuthority (line 17) | @HandleBeforeSave
method checkDeleteAuthority (line 22) | @HandleBeforeDelete
method checkUpdateLinkAuthority (line 27) | @HandleBeforeLinkSave
method checkDeleteLinkAuthority (line 35) | @HandleBeforeLinkDelete
FILE: src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeRepository.java
type WorkTimeRepository (line 16) | public interface WorkTimeRepository extends CrudRepository<WorkTime, Lon...
method findAll (line 18) | @Override
method findAll (line 22) | @Override
method findOne (line 26) | @Override
method findByEmployeeAndDateOrderByStartTimeAsc (line 30) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') or #employee.email == princi...
method findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc (line 33) | @PreAuthorize("hasRole('ROLE_SUPERVISOR') or #employee.email == princi...
method findByProjectAndDateBetweenOrderByDateAscStartTimeAsc (line 38) | @PreAuthorize("hasRole('ROLE_SUPERVISOR')")
method findByDateBetween (line 43) | @PreAuthorize("hasRole('ROLE_ADMIN')")
FILE: src/main/java/de/techdev/trackr/domain/scheduling/LastWorkdayDayOfMonthTrigger.java
class LastWorkdayDayOfMonthTrigger (line 27) | @Setter
method getHolidaysForMonth (line 43) | protected List<LocalDate> getHolidaysForMonth(FederalState state, Loca...
method lastWeekdayInMonth (line 59) | protected LocalDate lastWeekdayInMonth(LocalDate month, List<LocalDate...
method isWorkday (line 74) | protected boolean isWorkday(LocalDate date, List<LocalDate> holidays) {
method nextExecutionTime (line 79) | @Override
method nextExecutionTimeInternal (line 84) | protected LocalDate nextExecutionTimeInternal(TriggerContext triggerCo...
FILE: src/main/java/de/techdev/trackr/domain/scheduling/ScheduledJobsConfiguration.java
class ScheduledJobsConfiguration (line 30) | @Configuration
method vacationScheduledJobs (line 34) | @Bean
method employeeScheduledJob (line 39) | @Bean
method lastWorkdayDayOfMonthTrigger (line 44) | @Bean
method invoiceScheduledJob (line 50) | @Bean
method configureTasks (line 55) | @Override
method taskExecutor (line 68) | @Bean(destroyMethod = "shutdownNow")
method createSchedulerSecurityContext (line 78) | private SecurityContext createSchedulerSecurityContext() {
FILE: src/main/java/de/techdev/trackr/domain/translations/TranslationController.java
class TranslationController (line 23) | @Controller
method getTranslations (line 34) | @RequestMapping(method = RequestMethod.GET)
method setLocale (line 48) | @RequestMapping(method = RequestMethod.PUT, produces = MediaType.TEXT_...
FILE: src/main/java/de/techdev/trackr/domain/validation/EndAfterBeginValidator.java
class EndAfterBeginValidator (line 13) | public class EndAfterBeginValidator implements ConstraintValidator<EndAf...
method initialize (line 19) | @Override
method isValid (line 26) | @Override
FILE: src/main/java/de/techdev/trackr/domain/validation/ProjectBelongsToCompanyValidator.java
class ProjectBelongsToCompanyValidator (line 14) | public class ProjectBelongsToCompanyValidator implements ConstraintValid...
method initialize (line 20) | @Override
method isValid (line 27) | @Override
FILE: src/main/java/de/techdev/trackr/util/LocalDateUtil.java
class LocalDateUtil (line 13) | public final class LocalDateUtil {
method LocalDateUtil (line 15) | private LocalDateUtil() {
method fromLocalDate (line 18) | public static Date fromLocalDate(LocalDate date) {
method fromDate (line 23) | public static LocalDate fromDate(Date date) {
FILE: src/main/resources/data.sql
type uuid_mapping (line 1) | CREATE TABLE IF NOT EXISTS uuid_mapping (id int, uuid varchar)
FILE: src/main/resources/db/migration/V11__add_travel_expense_report_comments.sql
type TravelExpenseReportComment (line 1) | create table TravelExpenseReportComment (
FILE: src/main/resources/db/migration/V14__add_uuid_mapping.sql
type uuid_mapping (line 1) | CREATE TABLE uuid_mapping (
FILE: src/main/resources/db/migration/V15__migrate_credentials.sql
type Settings (line 13) | CREATE TABLE Settings (
FILE: src/main/resources/db/migration/V1__create_schema.sql
type Address (line 1) | create table Address (
type Authority (line 12) | create table Authority (
type BillableTime (line 19) | create table BillableTime (
type Company (line 30) | create table Company (
type ContactPerson (line 39) | create table ContactPerson (
type Credential (line 51) | create table Credential (
type Credential_Authority (line 59) | create table Credential_Authority (
type Employee (line 64) | create table Employee (
type Holiday (line 80) | create table Holiday (
type Project (line 88) | create table Project (
type VacationRequest (line 102) | create table VacationRequest (
type WorkTime (line 116) | create table WorkTime (
type TravelExpense (line 128) | create table TravelExpense (
type TravelExpenseReport (line 141) | create table TravelExpenseReport (
FILE: src/main/resources/db/migration/V4__add_invoices.sql
type Invoice (line 1) | create table Invoice (
FILE: src/main/resources/db/migration/V8__add_sick_days.sql
type SickDays (line 1) | create table SickDays (
FILE: src/test/java/de/techdev/test/FlywayTest.java
class FlywayTest (line 16) | @RunWith(SpringRunner.class)
class FlywayTestConfig (line 20) | public static class FlywayTestConfig {
method dataSource (line 22) | @Bean
method migrationSucceeds (line 32) | @Test
FILE: src/test/java/de/techdev/test/InMemoryOAuth2ResourceServerConfiguration.java
class InMemoryOAuth2ResourceServerConfiguration (line 14) | @Configuration
method oauthDataSource (line 18) | @Override
method tokenStore (line 23) | @Override
FILE: src/test/java/de/techdev/test/TestConstants.java
class TestConstants (line 3) | public class TestConstants {
FILE: src/test/java/de/techdev/test/TransactionalIntegrationTest.java
class TransactionalIntegrationTest (line 14) | @SpringBootTest(classes = { Trackr.class })
FILE: src/test/java/de/techdev/test/oauth/OAuthTestExecutionListener.java
class OAuthTestExecutionListener (line 29) | @Slf4j
method OAuthTestExecutionListener (line 36) | public OAuthTestExecutionListener() {
method beforeTestMethod (line 42) | @Override
method insertOauthTokenIntoStore (line 57) | private void insertOauthTokenIntoStore(TestContext testContext, @Nonnu...
method getAuthenticationFromAnnotation (line 62) | private Authentication getAuthenticationFromAnnotation(OAuthRequest to...
method afterTestMethod (line 104) | @Override
FILE: src/test/java/de/techdev/test/rest/AbstractDomainResourceSecurityTest.java
class AbstractDomainResourceSecurityTest (line 11) | public abstract class AbstractDomainResourceSecurityTest extends Abstrac...
method getResourceName (line 18) | protected abstract String getResourceName();
method getJsonEntity (line 20) | private HttpEntity<String> getJsonEntity(String content) {
method root (line 27) | protected ResponseEntity root() throws Exception {
method one (line 31) | protected ResponseEntity one(Long id) throws Exception {
method oneUrl (line 35) | protected ResponseEntity oneUrl(String url) throws Exception {
method create (line 39) | protected ResponseEntity create(String payload) throws Exception {
method update (line 43) | protected ResponseEntity update(Long id, String payload) throws Except...
method updateLink (line 53) | protected ResponseEntity updateLink(Long id, String linkName, String l...
method updateViaPatch (line 60) | protected ResponseEntity updateViaPatch(Long id, String patch) throws ...
method remove (line 64) | protected ResponseEntity remove(Long id) throws Exception {
method removeUrl (line 68) | protected ResponseEntity removeUrl(String url) throws Exception {
FILE: src/test/java/de/techdev/test/rest/AbstractJsonGenerator.java
class AbstractJsonGenerator (line 12) | public abstract class AbstractJsonGenerator<T, B extends AbstractJsonGen...
method AbstractJsonGenerator (line 18) | public AbstractJsonGenerator() {
method start (line 22) | public B start() {
method apply (line 32) | public final B apply(Consumer<T> function) {
method build (line 40) | public String build() {
method getJsonRepresentation (line 47) | protected abstract String getJsonRepresentation(T object);
method getNewTransientObject (line 53) | protected abstract T getNewTransientObject(int i);
method getSelf (line 58) | protected abstract B getSelf();
method reset (line 63) | protected void reset() {
FILE: src/test/java/de/techdev/test/rest/AbstractRestIntegrationTest.java
class AbstractRestIntegrationTest (line 21) | @RunWith(SpringRunner.class)
method setUpMvcFields (line 34) | @Before
FILE: src/test/java/de/techdev/test/rest/DomainResourceTestMatchers.java
class DomainResourceTestMatchers (line 11) | public class DomainResourceTestMatchers {
method DomainResourceTestMatchers (line 13) | private DomainResourceTestMatchers() {
type ConsumerWithException (line 20) | @FunctionalInterface
method accept (line 22) | public void accept(T item) throws Exception;
class ResultActionsMatcher (line 25) | private static class ResultActionsMatcher extends TypeSafeMatcher<Resp...
method ResultActionsMatcher (line 29) | protected ResultActionsMatcher(String description, ConsumerWithExcep...
method matchesSafely (line 34) | @Override
method describeTo (line 44) | @Override
method isAccessible (line 53) | public static Matcher<? super ResponseEntity> isAccessible() {
method isCreated (line 60) | public static Matcher<? super ResponseEntity> isCreated() {
method isForbidden (line 67) | public static Matcher<? super ResponseEntity> isForbidden() {
method isUpdated (line 74) | public static Matcher<? super ResponseEntity> isUpdated() {
method isNoContent (line 81) | public static Matcher<? super ResponseEntity> isNoContent() {
method isMethodNotAllowed (line 88) | public static Matcher<? super ResponseEntity> isMethodNotAllowed() {
FILE: src/test/java/de/techdev/test/rest/TestRestTemplate.java
class TestRestTemplate (line 29) | public class TestRestTemplate extends RestTemplate {
method TestRestTemplate (line 36) | public TestRestTemplate(String token, HttpClientOption... httpClientOp...
method addAuthentication (line 50) | private void addAuthentication(String token) {
type HttpClientOption (line 64) | public static enum HttpClientOption {
class BearerAuthorizationInterceptor (line 78) | private static class BearerAuthorizationInterceptor implements
method BearerAuthorizationInterceptor (line 83) | public BearerAuthorizationInterceptor(String token) {
method intercept (line 87) | @Override
class CustomHttpComponentsClientHttpRequestFactory (line 96) | protected static class CustomHttpComponentsClientHttpRequestFactory ex...
method CustomHttpComponentsClientHttpRequestFactory (line 103) | public CustomHttpComponentsClientHttpRequestFactory(
method createHttpContext (line 112) | @Override
method getRequestConfig (line 119) | protected RequestConfig getRequestConfig() {
FILE: src/test/java/de/techdev/trackr/core/web/converters/DateConverterTest.java
class DateConverterTest (line 16) | public class DateConverterTest {
method setUp (line 20) | @Before
method convert10 (line 25) | @Test
method convert19 (line 33) | @Test
method convertNull (line 41) | @Test
method convertWrongLength (line 47) | @Test(expected = IllegalArgumentException.class)
FILE: src/test/java/de/techdev/trackr/domain/common/FederalStateControllerIntegrationTest.java
class FederalStateControllerIntegrationTest (line 11) | @OAuthRequest
method getAllFederalStates (line 14) | @Test
FILE: src/test/java/de/techdev/trackr/domain/common/UuidMapperIntegrationTest.java
class UuidMapperIntegrationTest (line 17) | @Sql(TestConstants.CREATE_UUID_MAPPING_TABLE_SQL_FILE)
method insertUuid (line 23) | @Test
method findUuid (line 29) | @Test
method deleteUuidByUuid (line 36) | @Test
method deleteById (line 44) | @Test
FILE: src/test/java/de/techdev/trackr/domain/common/UuidMapperTest.java
class UuidMapperTest (line 9) | public class UuidMapperTest {
method setUp (line 13) | @Before
method extractUuid (line 18) | @Test
method extractUuidWithPrefix (line 24) | @Test
method extractUuidWithPrefixAndSuffix (line 30) | @Test
FILE: src/test/java/de/techdev/trackr/domain/company/AddressJsonGenerator.java
class AddressJsonGenerator (line 8) | public class AddressJsonGenerator extends AbstractJsonGenerator<Address,...
method getJsonRepresentation (line 10) | @Override
method getNewTransientObject (line 30) | @Override
method getSelf (line 43) | @Override
FILE: src/test/java/de/techdev/trackr/domain/company/AddressResourceSecurityTest.java
class AddressResourceSecurityTest (line 11) | @Sql("address/resourceTest.sql")
method getResourceName (line 18) | @Override
method findAllNotExported (line 23) | @Test
method one (line 29) | @Test
method createAllowedForAdmin (line 35) | @Test
method putAllowedForAdmin (line 41) | @Test
method patchAllowedForAdmin (line 47) | @Test
method createNotAllowedForSupervisor (line 52) | @Test
method putForbiddenForSupervisor (line 59) | @Test
method patchForbiddenForSupervisor (line 66) | @Test
method deleteNotExported (line 72) | @Test
FILE: src/test/java/de/techdev/trackr/domain/company/CompanyJsonGenerator.java
class CompanyJsonGenerator (line 8) | public class CompanyJsonGenerator extends AbstractJsonGenerator<Company,...
method withAddressId (line 12) | public CompanyJsonGenerator withAddressId(Long addressId) {
method getJsonRepresentation (line 17) | @Override
method getNewTransientObject (line 39) | @Override
method getSelf (line 49) | @Override
method reset (line 54) | @Override
FILE: src/test/java/de/techdev/trackr/domain/company/CompanyRepositoryTest.java
class CompanyRepositoryTest (line 9) | @Sql("repositoryTest.sql")
method deleteWithContactPersons (line 16) | @Test
method deleteWithProject (line 21) | @Test
FILE: src/test/java/de/techdev/trackr/domain/company/CompanyResourceSecurityTest.java
class CompanyResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootAccessible (line 25) | @Test
method one (line 31) | @Test
method findByNameLikeOrderByNameAsc (line 37) | @Test
method findByCompanyId (line 44) | @Test
method postAllowedForAdmin (line 51) | @Test
method putAllowedForAdmin (line 57) | @Test
method patchAllowedForAdmin (line 63) | @Test
method postForbiddenForSupervisor (line 68) | @Test
method putForbiddenForSupervisor (line 75) | @Test
method patchForbiddenForSupervisor (line 82) | @Test
method addContactPersonSupervisor (line 88) | @Test
method addContactForbiddenForEmployee (line 94) | @Test
method deleteContactAllowedForSupervisor (line 100) | @Test
method deleteContactNotAllowedForEmployee (line 106) | @Test
method deleteAllowedForAdmin (line 112) | @Test
method deleteForbiddenForSupervisor (line 117) | @Test
method getAddress (line 123) | @Test
FILE: src/test/java/de/techdev/trackr/domain/company/ContactPersonJsonGenerator.java
class ContactPersonJsonGenerator (line 8) | public class ContactPersonJsonGenerator extends AbstractJsonGenerator<Co...
method withCompanyId (line 12) | public ContactPersonJsonGenerator withCompanyId(Long companyId) {
method getJsonRepresentation (line 17) | @Override
method getNewTransientObject (line 42) | @Override
method getSelf (line 56) | @Override
method reset (line 61) | @Override
FILE: src/test/java/de/techdev/trackr/domain/company/ContactPersonResourceSecurityTest.java
class ContactPersonResourceSecurityTest (line 16) | @Sql("contactPerson/resourceTest.sql")
method getResourceName (line 23) | @Override
method rootAccessible (line 28) | @Test
method one (line 34) | @Test
method postAllowedForSupervisor (line 40) | @Test
method putAllowedForSupervisor (line 46) | @Test
method putNotAllowedForEmployee (line 52) | @Test
method patchAllowedForSupervisor (line 59) | @Test
method patchNotAllowedForEmployee (line 64) | @Test
method postNotAllowedForEmployee (line 70) | @Test
method deleteAllowedForSupervisor (line 86) | @Test
method deleteForbiddenForEmployee (line 91) | @Test
method updateCompanyForbiddenForEmployee (line 97) | @Test
method updateCompanyAllowedForSupervisor (line 107) | @Test
method deleteCompanyForbiddenForSupervisor (line 116) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/EmployeeControllerSecurityTest.java
class EmployeeControllerSecurityTest (line 25) | @Sql("resourceTest.sql")
method setUp (line 32) | @Before
method updateSelfViaPut (line 43) | @Test
method updateOtherViaPutIsForbidden (line 55) | @Test
method accessSelf (line 68) | @Test
method generateEmployeeJson (line 74) | protected String generateEmployeeJson(SelfEmployee selfEmployee) {
FILE: src/test/java/de/techdev/trackr/domain/employee/EmployeeJsonGenerator.java
class EmployeeJsonGenerator (line 13) | public class EmployeeJsonGenerator extends AbstractJsonGenerator<Employe...
method getJsonRepresentation (line 15) | @Override
method getNewTransientObject (line 52) | @Override
method getSelf (line 68) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceIntegrationTest.java
class EmployeeResourceIntegrationTest (line 19) | @Sql(scripts = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, e...
method creatingAnEmployeeViaRestAlsoCreatesInitialLocaleSettings (line 27) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceSecurityTest.java
class EmployeeResourceSecurityTest (line 15) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootNotAllowedForEmployees (line 25) | @Test
method rootAllowedForSupervisors (line 31) | @Test
method oneIsAllowedForSupervisor (line 36) | @Test
method oneIsAllowedForSelf (line 41) | @Test
method oneIsForbiddenForOtherEmployee (line 47) | @Test
method deleteAllowedForAdmins (line 68) | @Test
method deleteForbiddenForSupervisor (line 84) | @Test
method getJsonRepresentation (line 89) | protected String getJsonRepresentation(Employee employee) {
FILE: src/test/java/de/techdev/trackr/domain/employee/SelfEmployeeRepositoryTest.java
class SelfEmployeeRepositoryTest (line 21) | @RunWith(MockitoJUnitRunner.class)
method setUp (line 33) | @Before
method updateSelfUpdatesAllAllowedFields (line 44) | @Test
method updateSelfDoesNotUpdateForbiddenFields (line 59) | @Test
method updateSelfUpdatesTheAddressWhenItIsNotNull (line 71) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerSecurityTest.java
class AddressBookControllerSecurityTest (line 11) | @OAuthRequest
method rootIsAccessible (line 14) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerTest.java
class AddressBookControllerTest (line 13) | public class AddressBookControllerTest {
method setUp (line 17) | @Before
method transformEmployees (line 22) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseJsonGenerator.java
class TravelExpenseJsonGenerator (line 11) | public class TravelExpenseJsonGenerator extends AbstractJsonGenerator<Tr...
method withReportId (line 15) | public TravelExpenseJsonGenerator withReportId(Long reportId) {
method getJsonRepresentation (line 20) | @Override
method getNewTransientObject (line 50) | @Override
method getSelf (line 63) | @Override
method reset (line 68) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseResourceSecurityTest.java
class TravelExpenseResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootNotExported (line 25) | @Test
method oneForbiddenForOther (line 31) | @Test
method oneAllowedForSelf (line 37) | @Test
method createAllowedForSelf (line 42) | @Test
method createNotAllowedForOther (line 48) | @Test
method updateAllowedForSelf (line 56) | @Test
method deletePendingAllowed (line 62) | @Test
method deleteAcceptedNotAllowed (line 67) | @Test
method deleteSubmittedNotAllowed (line 72) | @Test
method changeReportNotAllowed (line 77) | @Test
method accessTypes (line 83) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportJsonGenerator.java
class ReportJsonGenerator (line 11) | public class ReportJsonGenerator extends AbstractJsonGenerator<Report, R...
method withEmployeeId (line 17) | public ReportJsonGenerator withEmployeeId(Long employeeId) {
method withDebitorId (line 22) | public ReportJsonGenerator withDebitorId(Long debitorId) {
method withProjectId (line 27) | public ReportJsonGenerator withProjectId(Long projectId) {
method getJsonRepresentation (line 32) | @Override
method getNewTransientObject (line 64) | @Override
method getSelf (line 74) | @Override
method reset (line 79) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportResourceSecurityTest.java
class ReportResourceSecurityTest (line 15) | @Sql("resourceTest.sql")
method getResourceName (line 22) | @Override
method rootNotExported (line 27) | @Test
method oneAllowedForSupervisor (line 33) | @Test
method oneNotAllowedForOther (line 39) | @Test
method oneAllowedForSelf (line 45) | @Test
method createAllowed (line 50) | @Test
method updateNotAllowedForSelf (line 56) | @Test
method updateForbiddenForOther (line 62) | @Test
method deleteAllowedForOwnerIfPending (line 70) | @Test
method deleteForbiddenForOwnerIfSubmitted (line 75) | @Test
method deleteAllowedForAdmin (line 80) | @Test
method deleteForbiddenForOtherEvenIfPending (line 86) | @Test
method pdfExport (line 92) | @Test
method pdfExportAsEmployee (line 99) | @Test
method updateEmployeeNotAllowedForSupervisor (line 105) | @Test
method addTravelExpenseAllowedForSelf (line 111) | @Test
method addTravelExpenseNotAllowedForOther (line 117) | @Test
method submitNotAllowedForOtherSupervisor (line 123) | @Test
method approveNotAllowedForOwningSupervisor (line 130) | @Test
method approveAllowedForSupervisor (line 137) | @Test
method rejectAllowedForSupervisor (line 144) | @Test
method findByStatusAllowedForSupervisor (line 151) | @Test
method findByStatusNotAllowedForEmployee (line 158) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportServiceTest.java
class ReportServiceTest (line 27) | @RunWith(MockitoJUnitRunner.class)
method setUp (line 42) | @Before
method testReject (line 47) | @Test
method testApprove (line 56) | @Test
method testSubmit (line 65) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentJsonGenerator.java
class CommentJsonGenerator (line 11) | public class CommentJsonGenerator extends AbstractJsonGenerator<Comment,...
method getJsonRepresentation (line 16) | @Override
method withReportId (line 34) | public CommentJsonGenerator withReportId(Long reportId) {
method withEmployeeId (line 39) | public CommentJsonGenerator withEmployeeId(Long employeeId) {
method getNewTransientObject (line 44) | @Override
method getSelf (line 52) | @Override
method reset (line 57) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentResourceSecurityTest.java
class CommentResourceSecurityTest (line 11) | @Sql("resourceTest.sql")
method getResourceName (line 18) | @Override
method rootNotExported (line 23) | @Test
method oneNotExported (line 28) | @Test
method createAllowedForOwningEmployee (line 33) | @Test
method createAllowedForSupervisor (line 39) | @Test
method updateForbidden (line 46) | @Test
method deleteNotExported (line 53) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/login/PrincipalControllerSecurityTest.java
class PrincipalControllerSecurityTest (line 12) | @OAuthRequest
method principal (line 17) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysJsonGenerator.java
class SickDaysJsonGenerator (line 11) | public class SickDaysJsonGenerator extends AbstractJsonGenerator<SickDay...
method withEmployeeId (line 15) | public SickDaysJsonGenerator withEmployeeId(Long employeeId) {
method getJsonRepresentation (line 20) | @Override
method getNewTransientObject (line 43) | @Override
method getSelf (line 54) | @Override
method reset (line 59) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysResourceSecurityTest.java
class SickDaysResourceSecurityTest (line 12) | @Sql("resourceTest.sql")
method getResourceName (line 19) | @Override
method rootIsNotAccessibleForAdmin (line 24) | @Test
method oneIsAllowedForEmployee (line 30) | @Test
method oneIsForbiddenForOther (line 35) | @Test
method createIsAllowedForEmployee (line 41) | @Test
method createIsForbiddenForOther (line 47) | @Test
method deleteIsAllowedForAdmin (line 56) | @Test
method deleteIsForbiddenForSupervisor (line 62) | @Test
method updateIsAllowedForEmployee (line 68) | @Test
method updateIsForbiddenForOther (line 74) | @Test
method findByEmployeeIsAllowedForEmployee (line 83) | @Test
method findByEmployeeIsForbiddenForOther (line 88) | @Test
method findByStartDateBetweenOrEndDateBetweenIsAllowedForAdmin (line 96) | @Test
method findByStartDateBetweenOrEndDateBetweenIsForbiddenForSupervisor (line 104) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculatorTest.java
class HolidayCalculatorTest (line 18) | public class HolidayCalculatorTest {
method setUp (line 22) | @Before
method calculateDifferenceBetweenExcludingHolidaysAndWeekends (line 27) | @Test
method calculateDifferenceBetweenExcludingHolidaysAndWeekendsAgain (line 35) | @Test
method calculateDifferenceBetweenExcludingHolidaysAndWeekendsLastDayWeekend (line 43) | @Test
method isWeekendOrHolidaySaturday (line 51) | @Test
method isWeekendOrHolidaySunday (line 58) | @Test
method isWeekendOrHolidayInList (line 65) | @Test
method getHolidaysAsDates (line 72) | private List<LocalDate> getHolidaysAsDates() {
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayResourceTest.java
class HolidayResourceTest (line 12) | @Sql("holiday/resourceTest.sql")
method getResourceName (line 17) | @Override
method rootAccessible (line 22) | @Test
method oneAccessible (line 27) | @Test
method createNotExported (line 32) | @Test
method updateNotExported (line 37) | @Test
method deleteNotExported (line 42) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestControllerSecurityTest.java
class VacationRequestControllerSecurityTest (line 20) | @Sql("resourceTest.sql")
method approveNotAllowedForSupervisorOnOwnVacationRequest (line 26) | @Test
method approveNotAllowedForEmployees (line 35) | @Test
method approveAllowedForOtherSupervisor (line 44) | @Test
method rejectAllowedForSupervisor (line 53) | @Test
method selfRejectForbiddenForSupervisor (line 62) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestJsonGenerator.java
class VacationRequestJsonGenerator (line 10) | public class VacationRequestJsonGenerator extends AbstractJsonGenerator<...
method withEmployeeId (line 15) | public VacationRequestJsonGenerator withEmployeeId(Long employeeId) {
method withApproverId (line 20) | public VacationRequestJsonGenerator withApproverId(Long approverId) {
method getJsonRepresentation (line 25) | @Override
method getNewTransientObject (line 61) | @Override
method getSelf (line 70) | @Override
method reset (line 75) | @Override
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepositoryTest.java
class VacationRequestRepositoryTest (line 18) | @Sql("repositoryTest.sql")
method findBySubmissionTimeBefore (line 25) | @Test
method findByApprovedBetween (line 32) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestResourceSecurityTest.java
class VacationRequestResourceSecurityTest (line 14) | @Sql("resourceTest.sql")
method getResourceName (line 22) | @Override
method rootNotExported (line 27) | @Test
method oneAllowedForEmployee (line 32) | @Test
method oneForbiddenForOther (line 37) | @Test
method findByEmployeeOrderByStartDateAscAllowedForEmployee (line 43) | @Test
method findByEmployeeOrderByStartDateAscAllowedForSupervisor (line 49) | @Test
method findByEmployeeOrderByStartDateAscForbiddenForOther (line 59) | @Test
method createAllowedForEmployee (line 67) | @Test
method createForbiddenForSupervisorIfNotOwner (line 73) | @Test
method updateForbiddenForEmployee (line 80) | @Test
method updateAllowedForSupervisor (line 86) | @Test
method updateSelfNotAllowedForSupervisor (line 93) | @Test
method updateForbiddenForOther (line 105) | @Test
method deleteAllowedForEmployee (line 113) | @Test
method deleteApprovedNotAllowedForEmployee (line 118) | @Test
method deleteRejectedNotAllowedForEmployee (line 124) | @Test
method deleteAllowedForSupervisor (line 130) | @Test
method deleteForbiddenForOwningSupervisor (line 136) | @Test
method deleteForbiddenForOther (line 142) | @Test
method updateEmployeeIsForbidden (line 148) | @Test
method updateApproverIsForbidden (line 154) | @Test
method deleteEmployeeIsForbidden (line 160) | @Test
method deleteApproverIsForbidden (line 165) | @Test
method getApprover (line 170) | @Test
method findByStatusOrderBySubmissionTimeAscForbiddenForEmployee (line 176) | @Test
method findByStatusOrderBySubmissionTimeAscAllowedForSupervisor (line 182) | @Test
method daysPerEmployeeBetweenAccessibleForAdmin (line 189) | @Test
method daysPerEmployeeBetweenForbiddenForSupervisor (line 196) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobsTest.java
class VacationRequestScheduledJobsTest (line 11) | @RunWith(MockitoJUnitRunner.class)
method callsTheRightMethod (line 20) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveServiceTest.java
class MailApproveServiceTest (line 10) | public class MailApproveServiceTest {
method setUp (line 14) | @Before
method approveOrReject_approve (line 19) | @Test
method approveOrReject_reject (line 25) | @Test
method approveOrReject_exception (line 31) | @Test(expected = IllegalStateException.class)
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapperTest.java
class MessageWrapperTest (line 13) | public class MessageWrapperTest {
method getSender (line 15) | @Test
method getSenderReturnsNullWhenNotTechdev (line 23) | @Test
method getBodyPlaintext (line 31) | @Test
method getBodyMimeMultipart (line 39) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalServiceTest.java
class VacationRequestEmployeeToDaysTotalServiceTest (line 17) | public class VacationRequestEmployeeToDaysTotalServiceTest {
method setUp (line 21) | @Before
method testGetMinimum (line 26) | @Test
method testGetMaximum (line 34) | @Test
method mapEmployeesAndSumUp (line 42) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyServiceTest.java
class VacationRequestNotifyServiceTest (line 20) | @RunWith(MockitoJUnitRunner.class)
method setUp (line 31) | @Before
method sendNotificationApproved (line 39) | @Test
method sendNotificationRejected (line 50) | @Test
FILE: src/test/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderServiceIntegrationTest.java
class WorkTimeTrackingReminderServiceIntegrationTest (line 10) | @ContextConfiguration(classes = {ApiBeansConfiguration.class})
method remindEmployeesToTrackWorkTimes (line 16) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/ProjectJsonGenerator.java
class ProjectJsonGenerator (line 9) | public class ProjectJsonGenerator extends AbstractJsonGenerator<Project,...
method withCompanyId (line 14) | public ProjectJsonGenerator withCompanyId(Long companyId) {
method withDebitorId (line 19) | public ProjectJsonGenerator withDebitorId(Long debitorId) {
method getNewTransientObject (line 24) | @Override
method reset (line 37) | @Override
method getJsonRepresentation (line 43) | @Override
method getSelf (line 72) | @Override
FILE: src/test/java/de/techdev/trackr/domain/project/ProjectResourceSecurityTest.java
class ProjectResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootAccessible (line 25) | @Test
method one (line 31) | @Test
method createAllowedForAdmin (line 37) | @Test
method updateAllowedForAdmin (line 43) | @Test
method deleteAllowedForAdmin (line 49) | @Test
method createForbiddenForSupervisor (line 54) | @Test
method updateForbiddenForSupervisor (line 61) | @Test
method deleteForbiddenForSupervisor (line 68) | @Test
method setCompanyAllowedForAdmin (line 74) | @Test
method setCompanyForbiddenForSupervisor (line 79) | @Test
method setDebitorAllowedForAdmin (line 85) | @Test
method setDebitorForbiddenForSupervisor (line 90) | @Test
method setWorktimesAllowedForAdmin (line 96) | @Test
method setWorktimesForbiddenForSupervisor (line 101) | @Test
method deleteCompanyAllowedForAdmin (line 107) | @Test
method deleteCompanyForbiddenForSupervisor (line 112) | @Test
method deleteDebitorAllowedForAdmin (line 118) | @Test
method deleteDebitorForbiddenForSupervisor (line 123) | @Test
method deleteWorktimesAllowedForAdmin (line 129) | @Test
method deleteWorktimesForbiddenForSupervisor (line 134) | @Test
method getNewTransientObject (line 140) | public Project getNewTransientObject(int i) {
FILE: src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimeControllerIntegrationTest.java
class BillableTimeControllerIntegrationTest (line 12) | public class BillableTimeControllerIntegrationTest extends AbstractRestI...
method findEmployeeMappingByProjectAndDateBetweenForbiddenForEmployee (line 14) | @Test
method findEmployeeMappingByProjectAndDateBetweenAllowedForSupervisor (line 22) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimeResourceSecurityTest.java
class BillableTimeResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootNotExported (line 25) | @Test
method oneAllowedForSupervisor (line 30) | @Test
method oneForbiddenForEmployee (line 36) | @Test
method createAllowedForSupervisor (line 41) | @Test
method createForbiddenForEmployee (line 48) | @Test
method deleteAllowedForSupervisor (line 54) | @Test
method deleteForbiddenForEmployee (line 60) | @Test
method updateAllowedForSupervisor (line 65) | @Test
method updateForbiddenForEmployee (line 75) | @Test
method deleteEmployeeForbidden (line 82) | @Test
method deleteProjectForbidden (line 88) | @Test
method updateEmployeeAllowedForSupervisor (line 94) | @Test
method updateProjectAllowedForSupervisor (line 100) | @Test
method updateEmployeeForbiddenForEmployee (line 106) | @Test
method updateProjectForbiddenForEmployee (line 111) | @Test
method findByDateBetweenAllowedForAdmin (line 116) | @Test
method findByDateBetweenForbiddenForSupervisor (line 123) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimesJsonGenerator.java
class BillableTimesJsonGenerator (line 12) | public class BillableTimesJsonGenerator extends AbstractJsonGenerator<Bi...
method withEmployeeId (line 17) | public BillableTimesJsonGenerator withEmployeeId(Long employeeId) {
method withProjectId (line 22) | public BillableTimesJsonGenerator withProjectId(Long projectId) {
method getJsonRepresentation (line 27) | @Override
method getNewTransientObject (line 47) | @Override
method getSelf (line 56) | @Override
method reset (line 61) | @Override
FILE: src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandlerTest.java
class InvoiceEventHandlerTest (line 13) | public class InvoiceEventHandlerTest {
method setUp (line 17) | @Before
method testSetInvoiceStateIfNecessaryOverdue (line 22) | @Test
method testSetInvoiceStateIfNecessaryOutstanding (line 31) | @Test
method testSetDueDateFromTimeForPayment (line 40) | @Test
method testDontSetDueDateFromTimeForPaymentIfItIsFilled (line 52) | @Test
method testSetDueDateFromTimeForPaymentDontFailOnNoDebitor (line 65) | @Test
method testSetDueDateFromTimeForPaymentDontFailOnNoTimeForPayment (line 72) | @Test
method stateGetsSetToOverdueIfTimeForPaymentSetsDueDateInPast (line 82) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceJsonGenerator.java
class InvoiceJsonGenerator (line 11) | public class InvoiceJsonGenerator extends AbstractJsonGenerator<Invoice,...
method withDebitorId (line 15) | public InvoiceJsonGenerator withDebitorId(Long debitorId) {
method getJsonRepresentation (line 20) | @Override
method getNewTransientObject (line 42) | @Override
method getSelf (line 53) | @Override
method reset (line 58) | @Override
FILE: src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceResourceSecurityTest.java
class InvoiceResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootIsAccessibleForAdmin (line 25) | @Test
method rootIsForbiddenForSupervisor (line 30) | @Test
method oneIsAccessibleForAdmin (line 36) | @Test
method oneIsForbiddenForSupervisor (line 41) | @Test
method findByInvoiceStateIsAccessibleForAdmin (line 47) | @Test
method findByInvoiceStateIsForbiddenForSupervisor (line 52) | @Test
method findByIdentifierLikeAndInvoiceStateIsAccessibleForAdmin (line 58) | @Test
method findByIdentifierLikeAndInvoiceStateIsForbiddenForSupervisor (line 63) | @Test
method findByCreationDateBetweenAccessibleForAdmin (line 69) | @Test
method findByCreationDateBetweenForbiddenForSupervisor (line 75) | @Test
method adminCanCreate (line 82) | @Test
method supervisorCannotCreate (line 88) | @Test
method adminCanDelete (line 95) | @Test
method supervisorCannotDelete (line 100) | @Test
method adminCanSetPaid (line 106) | @Test
method supervisorCannotSetPaid (line 114) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/CustomWorkTimeTest.java
class CustomWorkTimeTest (line 15) | public class CustomWorkTimeTest {
method reduceAndSortWorktimes (line 16) | @Test
method reduceAndSortWorkTimesPreservesComments (line 24) | @Test
method createCustomWorkTimes (line 31) | private List<CustomWorkTime> createCustomWorkTimes() throws ParseExcep...
method customWorkTimeHourCalculation (line 48) | @Test
method customWorkTimeTransfersTheCommentFromTheWorkTime (line 58) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeControllerSecurityTest.java
class WorkTimeControllerSecurityTest (line 13) | @OAuthRequest
method findEmployeeMappingByProjectAndDateBetweenForbiddenForEmployee (line 16) | @Test
method findEmployeeMappingByProjectAndDateBetweenAllowedForSupervisor (line 23) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeControllerTest.java
class WorkTimeControllerTest (line 29) | @RunWith(MockitoJUnitRunner.class)
method convertStreamOfWorkTimesToMap (line 38) | @Test
method createTestWorktimes (line 51) | private List<WorkTime> createTestWorktimes() throws Exception {
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeJsonGenerator.java
class WorkTimeJsonGenerator (line 11) | public class WorkTimeJsonGenerator extends AbstractJsonGenerator<WorkTim...
method withEmployeeId (line 16) | public WorkTimeJsonGenerator withEmployeeId(Long employeeId) {
method withProjectId (line 21) | public WorkTimeJsonGenerator withProjectId(Long projectId) {
method getJsonRepresentation (line 26) | @Override
method getNewTransientObject (line 52) | @Override
method getSelf (line 62) | @Override
method reset (line 67) | @Override
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeRepositoryTest.java
class WorkTimeRepositoryTest (line 23) | @Sql("repositoryTest.sql")
method findByEmployeeAndDateOnlyRespectsDatePart (line 39) | @Test
method findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc (line 47) | @Test
method findByProjectAndDateBetweenOrderByDateAscStartTimeAsc (line 58) | @Test
FILE: src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeResourceSecurityTest.java
class WorkTimeResourceSecurityTest (line 13) | @Sql("resourceTest.sql")
method getResourceName (line 20) | @Override
method rootNotExported (line 25) | @Test
method oneAllowedForOwner (line 30) | @Test
method oneForbiddenForOther (line 35) | @Test
method createAllowedForEveryoneIfIsEmployee (line 41) | @Test
method updateAllowedForOwner (line 47) | @Test
method updateAllowedForAdmin (line 53) | @Test
method updateNotAllowedForSupervisor (line 60) | @Test
method deleteAllowedForOwner (line 67) | @Test
method deleteAllowedForAdmin (line 72) | @Test
method deleteNotAllowedForSupervisor (line 78) | @Test
method updateEmployeeNotAllowed (line 91) | @Test
method deleteEmployeeNotAllowed (line 97) | @Test
method deleteProjectNotAllowed (line 103) | @Test
method updateProjectAllowedForOwner (line 109) | @Test
method updateProjectAllowedForAdmin (line 114) | @Test
method updateProjectForbiddenForSupervisor (line 120) | @Test
method findByEmployeeAndDateOrderByStartTimeAscAllowedForOwner (line 126) | @Test
method findByEmployeeAndDateOrderByStartTimeAscAllowedForSupervisor (line 133) | @Test
method findByDateBetweenAllowedForAdmin (line 141) | @Test
method findByDateBetweenForbiddenForSupervisor (line 149) | @Test
method findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscAllowedForOwner (line 157) | @Test
method findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscAllowedForSupervisor (line 164) | @Test
method findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscForbiddenForOther (line 177) | @Test
method findByEmployeeAndDateOrderByStartTimeAscForbiddenForOther (line 191) | @Test
method findByProjectAndDateBetweenOrderByDateAscStartTimeAscAllowedForSupervisor (line 200) | @Test
method findByProjectAndDateBetweenOrderByDateAscStartTimeAscForbiddenForEmployee (line 208) | @Test
FILE: src/test/java/de/techdev/trackr/domain/scheduling/LastWorkdayDayOfMonthTriggerTest.java
class LastWorkdayDayOfMonthTriggerTest (line 29) | @RunWith(MockitoJUnitRunner.class)
method setUp (line 40) | @Before
method lastDayIsNotWeekend (line 53) | @Test
method lastDayIsSunday (line 60) | @Test
method lastDayIsSaturday (line 67) | @Test
method lastDayIsMondayAndHoliday (line 74) | @Test
method lastDayIsMondayAndHolidayAndTheFridayIsAHolidayToo (line 83) | @Test
method triggerThisMonthIfLastScheduledTimeIsNull (line 92) | @Test
method dontTriggerTwiceAMonth (line 99) | @Test
method getTriggerContextWithLastScheduledExecutionTime (line 106) | protected TriggerContext getTriggerContextWithLastScheduledExecutionTi...
FILE: src/test/java/de/techdev/trackr/domain/translations/TranslationControllerSecurityTest.java
class TranslationControllerSecurityTest (line 11) | @OAuthRequest
method testGetTranslationsIsAccessible (line 14) | @Test
FILE: src/test/java/de/techdev/trackr/domain/translations/TranslationControllerTest.java
class TranslationControllerTest (line 21) | @RunWith(MockitoJUnitRunner.class)
method testGetTranslations (line 33) | @Test
method testSetTranslations (line 41) | @Test
FILE: src/test/resources/de/techdev/trackr/domain/tableUuidMapping.sql
type uuid_mapping (line 1) | CREATE TABLE IF NOT EXISTS uuid_mapping (
Condensed preview — 245 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (611K chars).
[
{
"path": ".gitignore",
"chars": 183,
"preview": "# OS\napplication.pid\n\n# gradle / Maven\ntarget/\nbuild/\n.gradle/\n\n# IDEA\n.idea/\n*.iml\n*.ipr\natlassian-ide-plugin.xml\n\n# Ec"
},
{
"path": "LICENSE",
"chars": 1100,
"preview": "The MIT License\n\nCopyright (c) 2014 techdev Solutions UG http://techdev.de\n\nPermission is hereby granted, free of charge"
},
{
"path": "README.md",
"chars": 5824,
"preview": "trackr backend\n==============\n\nWhat is it?\n-------------\ntrackr is an application to track petty much everything that is"
},
{
"path": "application.yaml",
"chars": 1891,
"preview": "spring:\n jpa:\n hibernate:\n naming:\n physical-strategy: org.hibernate.boot.model.nami"
},
{
"path": "build.gradle",
"chars": 1920,
"preview": "plugins {\n id 'org.springframework.boot' version '1.5.19.RELEASE'\n}\n\napply plugin: 'java'\napply plugin: 'jacoco'\n\nsou"
},
{
"path": "gradle/wrapper/gradle-wrapper.properties",
"chars": 230,
"preview": "#Fri Jan 23 09:44:57 CET 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
},
{
"path": "gradlew",
"chars": 5080,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "src/main/java/de/techdev/trackr/Trackr.java",
"chars": 1343,
"preview": "package de.techdev.trackr;\n\nimport org.springframework.boot.ApplicationPid;\nimport org.springframework.boot.SpringApplic"
},
{
"path": "src/main/java/de/techdev/trackr/core/mail/GMailConfiguration.java",
"chars": 2399,
"preview": "package de.techdev.trackr.core.mail;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springfr"
},
{
"path": "src/main/java/de/techdev/trackr/core/mail/MailService.java",
"chars": 209,
"preview": "package de.techdev.trackr.core.mail;\n\nimport org.springframework.mail.SimpleMailMessage;\n\n/**\n * @author Moritz Schulze\n"
},
{
"path": "src/main/java/de/techdev/trackr/core/mail/support/AsyncMailService.java",
"chars": 962,
"preview": "package de.techdev.trackr.core.mail.support;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport org.springframework"
},
{
"path": "src/main/java/de/techdev/trackr/core/mail/support/NoOpJavaMailSender.java",
"chars": 2137,
"preview": "package de.techdev.trackr.core.mail.support;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.context.annot"
},
{
"path": "src/main/java/de/techdev/trackr/core/pdf/HtmlPdfConverter.java",
"chars": 1187,
"preview": "package de.techdev.trackr.core.pdf;\n\nimport com.itextpdf.text.DocumentException;\nimport org.xhtmlrenderer.pdf.ITextRende"
},
{
"path": "src/main/java/de/techdev/trackr/core/pdf/PdfCreationException.java",
"chars": 198,
"preview": "package de.techdev.trackr.core.pdf;\n\n/**\n * @author Moritz Schulze\n */\npublic class PdfCreationException extends Excepti"
},
{
"path": "src/main/java/de/techdev/trackr/core/pdf/PdfRenderer.java",
"chars": 1156,
"preview": "package de.techdev.trackr.core.pdf;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotati"
},
{
"path": "src/main/java/de/techdev/trackr/core/pdf/ThymeleafRenderer.java",
"chars": 1670,
"preview": "package de.techdev.trackr.core.pdf;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.thymeleaf.TemplateEngine;\nimport org.t"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/AuthorityService.java",
"chars": 359,
"preview": "package de.techdev.trackr.core.security;\n\nimport java.util.Collection;\n\n/**\n * Access GrantedAuthorities for Employees a"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/InMemoryAuthorityService.java",
"chars": 861,
"preview": "package de.techdev.trackr.core.security;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.do"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/InMemorySecurityConfiguration.java",
"chars": 2416,
"preview": "package de.techdev.trackr.core.security;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.do"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/MethodSecurityConfiguration.java",
"chars": 2559,
"preview": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.spri"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/OAuth2AuthorityService.java",
"chars": 903,
"preview": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.spri"
},
{
"path": "src/main/java/de/techdev/trackr/core/security/OAuth2ResourceServerConfiguration.java",
"chars": 3703,
"preview": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.spri"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/ApiRepositoryRestConfiguration.java",
"chars": 3555,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport de.techdev.trackr.core.web.converters.DateConverter;\nimport de.techdev.t"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/ApiWebMvcConfiguration.java",
"chars": 2606,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport de.techdev.trackr.core.web.converters.DateConverter;\nimport de.techdev.t"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/ArgumentResolverPagingAndSortingTemplateVariables.java",
"chars": 2679,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframework.dat"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/ExceptionHandlers.java",
"chars": 2366,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.anno"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/JsonMappingHandlerExceptionResolver.java",
"chars": 3897,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxm"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/api/RepositoryEntityLinksWithoutProjection.java",
"chars": 2567,
"preview": "package de.techdev.trackr.core.web.api;\n\nimport org.springframework.data.repository.support.Repositories;\nimport org.spr"
},
{
"path": "src/main/java/de/techdev/trackr/core/web/converters/DateConverter.java",
"chars": 1724,
"preview": "package de.techdev.trackr.core.web.converters;\n\nimport org.springframework.core.convert.converter.Converter;\n\nimport jav"
},
{
"path": "src/main/java/de/techdev/trackr/domain/ApiBeansConfiguration.java",
"chars": 3162,
"preview": "package de.techdev.trackr.domain;\n\nimport de.techdev.trackr.core.pdf.PdfRenderer;\nimport de.techdev.trackr.domain.common"
},
{
"path": "src/main/java/de/techdev/trackr/domain/common/EmployeeSettingsLocaleResolver.java",
"chars": 3573,
"preview": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.trackr.domain.employee.Settings;\nimport de.techdev.trackr.do"
},
{
"path": "src/main/java/de/techdev/trackr/domain/common/FederalState.java",
"chars": 905,
"preview": "package de.techdev.trackr.domain.common;\n\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\n/**\n * @author Moritz Sch"
},
{
"path": "src/main/java/de/techdev/trackr/domain/common/FederalStateController.java",
"chars": 718,
"preview": "package de.techdev.trackr.domain.common;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.stereoty"
},
{
"path": "src/main/java/de/techdev/trackr/domain/common/UuidMapper.java",
"chars": 2704,
"preview": "package de.techdev.trackr.domain.common;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.s"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/Address.java",
"chars": 559,
"preview": "package de.techdev.trackr.domain.company;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.co"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/AddressEventHandler.java",
"chars": 1253,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.HandleBeforeCreate;\nimpo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/AddressRepository.java",
"chars": 876,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data."
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/Company.java",
"chars": 1516,
"preview": "package de.techdev.trackr.domain.company;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.techd"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/CompanyEventHandler.java",
"chars": 1054,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springfram"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/CompanyRepository.java",
"chars": 572,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.spri"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/CompanyWithAddressAndContactPersonsProjection.java",
"chars": 506,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.uti"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/ContactPerson.java",
"chars": 799,
"preview": "package de.techdev.trackr.domain.company;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.co"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/ContactPersonEventHandler.java",
"chars": 1142,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springfram"
},
{
"path": "src/main/java/de/techdev/trackr/domain/company/ContactPersonRepository.java",
"chars": 227,
"preview": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.repository.CrudRepository;\n\n/**\n * @author Mo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/Employee.java",
"chars": 2564,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.tech"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeController.java",
"chars": 1779,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.sp"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeEventHandler.java",
"chars": 1291,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.sp"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeRepository.java",
"chars": 1841,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport org.springframew"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeScheduledJob.java",
"chars": 933,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.track"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/Projections.java",
"chars": 889,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.track"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/SelfEmployee.java",
"chars": 1171,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport lombok.Getter;\nimpor"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/SelfEmployeeRepository.java",
"chars": 1714,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.do"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/Settings.java",
"chars": 697,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.c"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/SettingsRepository.java",
"chars": 499,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.data.repository.Repository;\nimport org.springfram"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/addressbook/AddressBookController.java",
"chars": 2307,
"preview": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.tec"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/addressbook/EmployeeForAddressBookDTO.java",
"chars": 1222,
"preview": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techd"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpense.java",
"chars": 1196,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\ni"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseEventHandler.java",
"chars": 2387,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\ni"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseRepository.java",
"chars": 594,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport org.springframework.data.repository.CrudRepository;\nimport o"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseTypeController.java",
"chars": 756,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport org.springframework.http.MediaType;\nimport org.springframewo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Projections.java",
"chars": 1620,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de."
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Report.java",
"chars": 1600,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de."
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportController.java",
"chars": 3782,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.core.pdf.PdfCreationException;\nimp"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportEventHandler.java",
"chars": 2373,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport o"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportNotifyService.java",
"chars": 3457,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.t"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportRepository.java",
"chars": 1505,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport o"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportService.java",
"chars": 2441,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport d"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/Comment.java",
"chars": 846,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.Employee;"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentEventHandler.java",
"chars": 1016,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport org.springframework.data.rest.core.annotati"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentRepository.java",
"chars": 1097,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.expenses."
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentWithEmployeeProjection.java",
"chars": 451,
"preview": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.Employee;"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/login/PrincipalController.java",
"chars": 2255,
"preview": "package de.techdev.trackr.domain.employee.login;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.t"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/login/support/SupervisorService.java",
"chars": 1018,
"preview": "package de.techdev.trackr.domain.employee.login.support;\n\nimport de.techdev.trackr.core.security.AuthorityService;\nimpor"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDays.java",
"chars": 774,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysEventHandler.java",
"chars": 1383,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimpo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysNotifyService.java",
"chars": 1978,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.t"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysRepository.java",
"chars": 1445,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.sprin"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysWithEmployeeProjection.java",
"chars": 459,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.sprin"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/Holiday.java",
"chars": 523,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport lombok."
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculator.java",
"chars": 2102,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.tech"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayRepository.java",
"chars": 765,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport org.spr"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequest.java",
"chars": 1342,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport de.techd"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestApproveService.java",
"chars": 3690,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestController.java",
"chars": 3221,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.vacation.support.VacationR"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestEventHandler.java",
"chars": 3405,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepository.java",
"chars": 2299,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.sprin"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobs.java",
"chars": 623,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans."
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestWithEmployeeAndApproverProjection.java",
"chars": 645,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.sprin"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveService.java",
"chars": 4249,
"preview": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport d"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapper.java",
"chars": 2417,
"preview": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport javax.mail.Address;\nimport javax.mail.Message;\nimpor"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalService.java",
"chars": 3487,
"preview": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.employee.vacation.HolidayCa"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyService.java",
"chars": 2954,
"preview": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.t"
},
{
"path": "src/main/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderService.java",
"chars": 1814,
"preview": "package de.techdev.trackr.domain.employee.worktimetracking;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.t"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/Project.java",
"chars": 1509,
"preview": "package de.techdev.trackr.domain.project;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.techd"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/ProjectEventHandler.java",
"chars": 1001,
"preview": "package de.techdev.trackr.domain.project;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springfram"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/ProjectRepository.java",
"chars": 520,
"preview": "package de.techdev.trackr.domain.project;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.spri"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/ProjectWithCompanyAndDebitorProjection.java",
"chars": 620,
"preview": "package de.techdev.trackr.domain.project;\n\nimport de.techdev.trackr.domain.company.Company;\nimport org.springframework.d"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTime.java",
"chars": 954,
"preview": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeController.java",
"chars": 2054,
"preview": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springf"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeEventHandler.java",
"chars": 1076,
"preview": "package de.techdev.trackr.domain.project.billtimes;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org."
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeRepository.java",
"chars": 1286,
"preview": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springf"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeWithProjectProjection.java",
"chars": 459,
"preview": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springf"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/ChangeStateService.java",
"chars": 437,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n "
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/Invoice.java",
"chars": 1085,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport lombok.Getter"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceController.java",
"chars": 1098,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandler.java",
"chars": 2446,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.tr"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceOverdueService.java",
"chars": 1164,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.fa"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceRepository.java",
"chars": 1454,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.data.domain.Page;\nimport org.springframewo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceScheduledJob.java",
"chars": 533,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceWithDebitorProjection.java",
"chars": 590,
"preview": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport org.springfra"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/CustomWorkTime.java",
"chars": 2858,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.time.Durat"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/Projections.java",
"chars": 965,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTime.java",
"chars": 992,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeController.java",
"chars": 5099,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEmployee.java",
"chars": 2008,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEventHandler.java",
"chars": 1517,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.sprin"
},
{
"path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeRepository.java",
"chars": 2278,
"preview": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techde"
},
{
"path": "src/main/java/de/techdev/trackr/domain/scheduling/LastWorkdayDayOfMonthTrigger.java",
"chars": 3771,
"preview": "package de.techdev.trackr.domain.scheduling;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.tra"
},
{
"path": "src/main/java/de/techdev/trackr/domain/scheduling/ScheduledJobsConfiguration.java",
"chars": 3483,
"preview": "package de.techdev.trackr.domain.scheduling;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.tra"
},
{
"path": "src/main/java/de/techdev/trackr/domain/translations/TranslationController.java",
"chars": 2569,
"preview": "package de.techdev.trackr.domain.translations;\n\nimport de.techdev.trackr.domain.employee.Settings;\nimport de.techdev.tra"
},
{
"path": "src/main/java/de/techdev/trackr/domain/validation/EndAfterBeginValidator.java",
"chars": 1793,
"preview": "package de.techdev.trackr.domain.validation;\n\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimpo"
},
{
"path": "src/main/java/de/techdev/trackr/domain/validation/ProjectBelongsToCompanyValidator.java",
"chars": 1664,
"preview": "package de.techdev.trackr.domain.validation;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr."
},
{
"path": "src/main/java/de/techdev/trackr/domain/validation/constraints/EndAfterBegin.java",
"chars": 866,
"preview": "package de.techdev.trackr.domain.validation.constraints;\n\nimport de.techdev.trackr.domain.validation.EndAfterBeginValida"
},
{
"path": "src/main/java/de/techdev/trackr/domain/validation/constraints/ProjectBelongsToCompany.java",
"chars": 902,
"preview": "package de.techdev.trackr.domain.validation.constraints;\n\nimport de.techdev.trackr.domain.validation.ProjectBelongsToCom"
},
{
"path": "src/main/java/de/techdev/trackr/util/LocalDateUtil.java",
"chars": 745,
"preview": "package de.techdev.trackr.util;\n\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\ni"
},
{
"path": "src/main/resources/META-INF/mail-integration.xml",
"chars": 2047,
"preview": "<beans:beans xmlns=\"http://www.springframework.org/schema/integration\"\n xmlns:xsi=\"http://www.w3.org/2001/XM"
},
{
"path": "src/main/resources/banner.txt",
"chars": 4379,
"preview": " \n "
},
{
"path": "src/main/resources/data.sql",
"chars": 54876,
"preview": "CREATE TABLE IF NOT EXISTS uuid_mapping (id int, uuid varchar);\n\n/* EMPLOYEE ADDRESSES */\nINSERT INTO address (id, versi"
},
{
"path": "src/main/resources/db/migration/V10__modify_travel_expense_add_comment.sql",
"chars": 61,
"preview": "alter table TravelExpense\n add column comment varchar(255);\n"
},
{
"path": "src/main/resources/db/migration/V11__add_travel_expense_report_comments.sql",
"chars": 459,
"preview": "create table TravelExpenseReportComment (\n id int8 not null,\n submissionDate timestamp,\n text varchar(255),\n employe"
},
{
"path": "src/main/resources/db/migration/V12__modify_company_add_time_for_payment.sql",
"chars": 53,
"preview": "alter table Company\n add column timeForPayment int4;"
},
{
"path": "src/main/resources/db/migration/V13__modify_travel_expense_reports_add_debitor_and_project.sql",
"chars": 556,
"preview": "alter table TravelExpenseReport\n add column debitor_id int8 not null default 0;\n\nupdate TravelExpenseReport set debitor"
},
{
"path": "src/main/resources/db/migration/V14__add_uuid_mapping.sql",
"chars": 69,
"preview": "CREATE TABLE uuid_mapping (\n id int8 not null,\n uuid varchar(40)\n);"
},
{
"path": "src/main/resources/db/migration/V15__migrate_credentials.sql",
"chars": 816,
"preview": "ALTER TABLE Employee\n ADD COLUMN email VARCHAR(255);\n\nALTER TABLE Employee\n ADD UNIQUE (email);\n\n-- transfer the ema"
},
{
"path": "src/main/resources/db/migration/V16__add_holidays_2015.sql",
"chars": 3445,
"preview": "insert into holiday (id, day, name, federalstate) values (167, '2014-12-24', 'Weihnachten', 'BADEN_WUERTTEMBERG');\ninser"
},
{
"path": "src/main/resources/db/migration/V17__add_holidays_2015.sql",
"chars": 24538,
"preview": "-- 2015 - Baden Württemberg\ninsert into holiday (id, day, name, federalstate) values (199, '2015-01-01', 'Neujahr', 'BAD"
},
{
"path": "src/main/resources/db/migration/V18__expense_paid_marker.sql",
"chars": 64,
"preview": "ALTER TABLE travelexpense ADD COLUMN paid BOOLEAN DEFAULT false;"
},
{
"path": "src/main/resources/db/migration/V19__add_employee_address.sql",
"chars": 155,
"preview": "ALTER TABLE employee ADD COLUMN address_id int8;\nALTER TABLE employee ADD CONSTRAINT employee_contact_address FOREIGN KE"
},
{
"path": "src/main/resources/db/migration/V1__create_schema.sql",
"chars": 5353,
"preview": " create table Address (\n id int8 not null,\n city varchar(255),\n country varchar(255),\n ho"
},
{
"path": "src/main/resources/db/migration/V20__add_employe_deleted.sql",
"chars": 71,
"preview": "ALTER TABLE employee ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE;"
},
{
"path": "src/main/resources/db/migration/V2__add_roles.sql",
"chars": 588,
"preview": "insert into employee (id, version, firstName, lastName, title, hourlyCostRate, salary, federalState) values (0, 0, 'admi"
},
{
"path": "src/main/resources/db/migration/V3__add_holidays_2014.sql",
"chars": 18952,
"preview": "-- CLean-up\ndelete from holiday;\n\n-- 2014 - Baden Württemberg\ninsert into holiday (id, day, name, federalstate) values ("
},
{
"path": "src/main/resources/db/migration/V4__add_invoices.sql",
"chars": 373,
"preview": "create table Invoice (\n id int8 not null,\n creationDate date,\n dueDate date,\n identifier varchar(255),\n i"
},
{
"path": "src/main/resources/db/migration/V5__modify_vacationrequests.sql",
"chars": 71,
"preview": "alter table VacationRequest\n\talter column approvalDate type timestamp;\n"
},
{
"path": "src/main/resources/db/migration/V6__modify_travel_expense_reports_and_contact_persons.sql",
"chars": 131,
"preview": "alter table TravelExpenseReport\n add column submissionDate timestamp;\n\nalter table ContactPerson\n add column roles var"
},
{
"path": "src/main/resources/db/migration/V7__update_travel_expense_report_submission_date_from_travel_expenses.sql",
"chars": 178,
"preview": "UPDATE TravelExpenseReport ter\n\tSET submissionDate = (\n\t\tSELECT MAX(te.submissionDate)\n\t\tFROM TravelExpense te\n\t\tWHERE t"
},
{
"path": "src/main/resources/db/migration/V8__add_sick_days.sql",
"chars": 261,
"preview": "create table SickDays (\n id int8 not null,\n endDate date,\n startDate date,\n version int4,\n employee_id in"
},
{
"path": "src/main/resources/db/migration/V9__modify_travel_expense_report.sql",
"chars": 252,
"preview": "alter table TravelExpenseReport\n add column approvalDate timestamp;\n\nalter table TravelExpenseReport\n add column appro"
},
{
"path": "src/main/resources/i18n/trackr-de.json",
"chars": 9363,
"preview": "{\n \"AUTHORITY\": {\n \"ROLE_ADMIN\": \"Administrator\",\n \"ROLE_SUPERVISOR\": \"Supervisor\",\n \"ROLE_EMPLO"
},
{
"path": "src/main/resources/i18n/trackr-en.json",
"chars": 9117,
"preview": "{\n \"AUTHORITY\": {\n \"ROLE_ADMIN\": \"Administrator\",\n \"ROLE_SUPERVISOR\": \"Supervisor\",\n \"ROLE_EMPLO"
},
{
"path": "src/main/resources/i18n/validation/messages_de.properties",
"chars": 136,
"preview": "validation.date.endAfterBegin=Start darf nicht nach Ende sein\nvalidation.company.projectBelongsTo=Das Projekt muss zu de"
},
{
"path": "src/main/resources/i18n/validation/messages_en.properties",
"chars": 134,
"preview": "validation.date.endAfterBegin=Start must not be after end.\nvalidation.company.projectBelongsTo=The project must belong t"
},
{
"path": "src/main/resources/logback-console.xml",
"chars": 900,
"preview": "<configuration>\n\n <property name=\"charset\" value=\"UTF-8\"/>\n <property name=\"pattern\" value=\"%d{HH:mm:ss.SSS} [%thr"
},
{
"path": "src/main/resources/logback-file.xml",
"chars": 1458,
"preview": "<configuration>\n\n <property name=\"charset\" value=\"UTF-8\"/>\n <property name=\"pattern\" value=\"%d{HH:mm:ss.SSS} [%thr"
},
{
"path": "src/main/resources/pdfTemplates/travel-expenses/report.html",
"chars": 26055,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www."
},
{
"path": "src/test/java/de/techdev/test/FlywayTest.java",
"chars": 1116,
"preview": "package de.techdev.test;\n\nimport org.flywaydb.core.Flyway;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimpor"
},
{
"path": "src/test/java/de/techdev/test/InMemoryOAuth2ResourceServerConfiguration.java",
"chars": 857,
"preview": "package de.techdev.test;\n\nimport de.techdev.trackr.core.security.OAuth2ResourceServerConfiguration;\nimport org.springfra"
},
{
"path": "src/test/java/de/techdev/test/TestConstants.java",
"chars": 321,
"preview": "package de.techdev.test;\n\npublic class TestConstants {\n\n /**\n * Path to the SQL file that creates the uuid mappin"
},
{
"path": "src/test/java/de/techdev/test/TransactionalIntegrationTest.java",
"chars": 704,
"preview": "package de.techdev.test;\n\nimport de.techdev.trackr.Trackr;\nimport org.junit.runner.RunWith;\nimport org.springframework.b"
},
{
"path": "src/test/java/de/techdev/test/oauth/OAuthRequest.java",
"chars": 585,
"preview": "package de.techdev.test.oauth;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport stati"
},
{
"path": "src/test/java/de/techdev/test/oauth/OAuthTestExecutionListener.java",
"chars": 4337,
"preview": "package de.techdev.test.oauth;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.core.annotation.AnnotationU"
},
{
"path": "src/test/java/de/techdev/test/rest/AbstractDomainResourceSecurityTest.java",
"chars": 3134,
"preview": "package de.techdev.test.rest;\n\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\ni"
},
{
"path": "src/test/java/de/techdev/test/rest/AbstractJsonGenerator.java",
"chars": 1891,
"preview": "package de.techdev.test.rest;\n\nimport javax.json.Json;\nimport javax.json.stream.JsonGeneratorFactory;\nimport java.util.f"
},
{
"path": "src/test/java/de/techdev/test/rest/AbstractRestIntegrationTest.java",
"chars": 1663,
"preview": "package de.techdev.test.rest;\n\nimport de.techdev.test.InMemoryOAuth2ResourceServerConfiguration;\nimport de.techdev.test."
},
{
"path": "src/test/java/de/techdev/test/rest/DomainResourceTestMatchers.java",
"chars": 3188,
"preview": "package de.techdev.test.rest;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest.TypeSaf"
},
{
"path": "src/test/java/de/techdev/test/rest/TestRestTemplate.java",
"chars": 4606,
"preview": "package de.techdev.test.rest;\n\nimport org.apache.http.client.config.CookieSpecs;\nimport org.apache.http.client.config.Re"
},
{
"path": "src/test/java/de/techdev/trackr/core/web/converters/DateConverterTest.java",
"chars": 1423,
"preview": "package de.techdev.trackr.core.web.converters;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.text.Simple"
},
{
"path": "src/test/java/de/techdev/trackr/domain/common/FederalStateControllerIntegrationTest.java",
"chars": 667,
"preview": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstrac"
},
{
"path": "src/test/java/de/techdev/trackr/domain/common/UuidMapperIntegrationTest.java",
"chars": 1615,
"preview": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.test.TestConstants;\nimport de.techdev.test.TransactionalInte"
},
{
"path": "src/test/java/de/techdev/trackr/domain/common/UuidMapperTest.java",
"chars": 1079,
"preview": "package de.techdev.trackr.domain.common;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.Co"
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/AddressJsonGenerator.java",
"chars": 1439,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream."
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/AddressResourceSecurityTest.java",
"chars": 2374,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstra"
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/CompanyJsonGenerator.java",
"chars": 1646,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream."
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/CompanyRepositoryTest.java",
"chars": 816,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.techdev.test.r"
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/CompanyResourceSecurityTest.java",
"chars": 4217,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstra"
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/ContactPersonJsonGenerator.java",
"chars": 1926,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream."
},
{
"path": "src/test/java/de/techdev/trackr/domain/company/ContactPersonResourceSecurityTest.java",
"chars": 4323,
"preview": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstra"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeControllerSecurityTest.java",
"chars": 4262,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstr"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeJsonGenerator.java",
"chars": 2653,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr."
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceIntegrationTest.java",
"chars": 1965,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstr"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceSecurityTest.java",
"chars": 4021,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.Abstr"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/SelfEmployeeRepositoryTest.java",
"chars": 2958,
"preview": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.do"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerSecurityTest.java",
"chars": 672,
"preview": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.tes"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerTest.java",
"chars": 945,
"preview": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.ju"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseJsonGenerator.java",
"chars": 2425,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.js"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseResourceSecurityTest.java",
"chars": 2785,
"preview": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.r"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportJsonGenerator.java",
"chars": 2360,
"preview": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportResourceSecurityTest.java",
"chars": 6237,
"preview": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportServiceTest.java",
"chars": 2772,
"preview": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.trackr.domain.employee.EmployeeRepository;"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentJsonGenerator.java",
"chars": 1875,
"preview": "package de.techdev.trackr.domain.employee.expenses.report.comment;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\ni"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentResourceSecurityTest.java",
"chars": 2005,
"preview": "package de.techdev.trackr.domain.employee.expenses.report.comment;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/login/PrincipalControllerSecurityTest.java",
"chars": 846,
"preview": "package de.techdev.trackr.domain.employee.login;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysJsonGenerator.java",
"chars": 1909,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techde"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysResourceSecurityTest.java",
"chars": 4168,
"preview": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.r"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculatorTest.java",
"chars": 2964,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.time.L"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayResourceTest.java",
"chars": 1388,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.r"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestControllerSecurityTest.java",
"chars": 4092,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.TestConstants;\nimport de.techdev.test.oauth."
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestJsonGenerator.java",
"chars": 2771,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.js"
},
{
"path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepositoryTest.java",
"chars": 1719,
"preview": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.tech"
}
]
// ... and 45 more files (download for full content)
About this extraction
This page contains the full source code of the techdev-solutions/trackr-backend GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 245 files (553.9 KB), approximately 151.7k tokens, and a symbol index with 1087 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.